Skip to content

Commit

Permalink
Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
blaubaer committed Oct 11, 2024
1 parent 417c343 commit f92cd1c
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 126 deletions.
53 changes: 26 additions & 27 deletions cmd/build/build-image.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,27 @@ func newBuildImage(b *build) *buildImage {
return &buildImage{
build: b,

defaultGenericConfigFile: "contrib/configurations/dummy-for-oci-images.yaml",
defaultExtendedConfigFile: "contrib/configurations/sshd-dropin-replacement.yaml",
dummyConfiguration: "cmd/build/contrib/dummy-for-oci-images.yaml",
defaultConfiguration: "contrib/configurations/sshd-dropin-replacement.yaml",
}
}

type buildImage struct {
*build

defaultGenericConfigFile string
defaultExtendedConfigFile string
dummyConfiguration string
defaultConfiguration string
}

func (this *buildImage) attach(cmd *kingpin.CmdClause) {
cmd.Flag("defaultConfigFile", "").
Default(this.defaultGenericConfigFile).
cmd.Flag("dummyConfiguration", "").
Default(this.dummyConfiguration).
PlaceHolder("<file>").
StringVar(&this.defaultGenericConfigFile)
cmd.Flag("defaultExtendedConfigFile", "").
Default(this.defaultExtendedConfigFile).
StringVar(&this.dummyConfiguration)
cmd.Flag("defaultConfiguration", "").
Default(this.defaultConfiguration).
PlaceHolder("<file>").
StringVar(&this.defaultExtendedConfigFile)
StringVar(&this.defaultConfiguration)
}

func (this *buildImage) create(ctx context.Context, binary *buildArtifact) (_ buildArtifacts, rErr error) {
Expand Down Expand Up @@ -162,39 +162,38 @@ func (this *buildImage) createPart(ctx context.Context, binary *buildArtifact) (

img = mutate.Annotations(img, annotations).(gcv1.Image)

artifacts := common.Seq2ErrOf[imageArtifactLayerItem](imageArtifactLayerItem{
sourceFile: this.defaultExtendedConfigFile,
artifacts := []imageArtifactLayerItem{{
sourceFile: this.defaultConfiguration,
targetFile: binary.platform.os.bifroestConfigFilePath(),
mode: 0644,
})
if !a.os.isUnix() {
artifacts = common.Seq2ErrOf[imageArtifactLayerItem](imageArtifactLayerItem{
sourceFile: this.defaultGenericConfigFile,
targetFile: binary.platform.os.bifroestConfigFilePath(),
mode: 0644,
})
} else if strings.EqualFold(from, "scratch") {
artifacts = common.Seq2ErrOf[imageArtifactLayerItem](imageArtifactLayerItem{
sourceFile: this.defaultGenericConfigFile,
}}

if !a.os.isUnix() || strings.EqualFold(from, "scratch") {
artifacts = []imageArtifactLayerItem{{
sourceFile: this.dummyConfiguration,
targetFile: binary.platform.os.bifroestConfigFilePath(),
mode: 0644,
}, imageArtifactLayerItem{
sourceFile: "contrib/rootfs/etc/passwd",
}}
}

if a.os.isUnix() && strings.EqualFold(from, "scratch") {
artifacts = append(artifacts, imageArtifactLayerItem{
sourceFile: "cmd/build/contrib/passwd",
targetFile: "/etc/passwd",
mode: 0644,
}, imageArtifactLayerItem{
sourceFile: "contrib/rootfs/etc/group",
sourceFile: "cmd/build/contrib/group",
targetFile: "/etc/group",
mode: 0644,
}, imageArtifactLayerItem{
sourceFile: "contrib/rootfs/etc/shadow",
sourceFile: "cmd/build/contrib/shadow",
targetFile: "/etc/shadow",
mode: 0600,
})
}

binaryLayer, err := binary.toLayer(common.JoinSeq2[imageArtifactLayerItem, error](
artifacts,
common.Seq2ErrOf[imageArtifactLayerItem](artifacts...),
common.Seq2ErrOf[imageArtifactLayerItem](artifactDepItems...),
))
if err != nil {
Expand Down
31 changes: 31 additions & 0 deletions cmd/build/contrib/dummy-for-oci-images.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## This configuration should only be used as dummy configuration within OCI/Docker images.
## It will create (if not exists)
## for the regular sshd.

startMessage: >
Welcome to Engity's Bifröst!
This is instance runs with a demo configuration which should and is
NOT intended for production use. Therefore login to this instance
is not possible until it will be configured.
See https://bifroest.engity.org/latest/setup/ for more details.
ssh:
addresses: [ ":22" ]
banner: |+
Transcend with Engity's Bifröst
===============================
This is instance runs with a demo configuration which should
and is NOT intended for production use. Therefore login to
this instance is not possible until it will be configured.
See https://bifroest.engity.org/latest/setup/ for more details.
flows:
- name: default
authorization:
type: htpasswd
environment:
type: local
# This property will not be evaluated in Windows.
name: "demo"
1 change: 1 addition & 0 deletions cmd/build/contrib/group
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root:x:0:
1 change: 1 addition & 0 deletions cmd/build/contrib/passwd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root:x:0:0:root:/:/usr/bin/bifroest
1 change: 1 addition & 0 deletions cmd/build/contrib/shadow
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root:*:19683:0:99999:7:::
34 changes: 0 additions & 34 deletions contrib/configurations/dummy-for-oci-images.yaml

This file was deleted.

Empty file removed contrib/rootfs/etc/group
Empty file.
Empty file removed contrib/rootfs/etc/passwd
Empty file.
Empty file removed contrib/rootfs/etc/shadow
Empty file.
2 changes: 1 addition & 1 deletion docs/reference/connection/ssh.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ How many different authentication methods a client can use before the connection
<<property("maxConnections", "uint8", None, default=255)>>
The maximum amount of parallel connections on this service. Every additional connection beyond will be rejected.

<<property_with_holder("banner", "String Template", "../templating/index.md#string", "Connection", "../context/connection.md", default='{{ `/etc/ssh/sshd-banner` | file `optional` | default `Transcend with Engity Bifröst\n\n` }}')>>
<<property_with_holder("banner", "String Template", "../templating/index.md#string", "Connection", "../context/connection.md", default='{{ `/etc/ssh/sshd-banner` | file `optional` | default `Transcend with Engity's Bifröst\n\n` }}')>>
Banner which will be shown when the client connects to the server even before the first validation of authorizations or similar happens.

## Examples
Expand Down
66 changes: 3 additions & 63 deletions pkg/configuration/authorization-htpasswd.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
package configuration

import (
"crypto/rand"
"fmt"
"os"
"path/filepath"

log "github.com/echocat/slf4g"
"github.com/mr-tron/base58"
"golang.org/x/crypto/bcrypt"
"gopkg.in/yaml.v3"

"github.com/engity-com/bifroest/pkg/common"
"github.com/engity-com/bifroest/pkg/crypto"
"github.com/engity-com/bifroest/pkg/errors"
"github.com/engity-com/bifroest/pkg/sys"
)

Expand All @@ -26,9 +16,8 @@ var (
)

type AuthorizationHtpasswd struct {
File crypto.HtpasswdFile `yaml:"file,omitempty"`
Entries crypto.Htpasswd `yaml:"entries,omitempty"`
GenerateWithUserIfAbsentAndWarn bool `yaml:"generateWithUserIfAbsentAndWarn"`
File crypto.HtpasswdFile `yaml:"file,omitempty"`
Entries crypto.Htpasswd `yaml:"entries,omitempty"`
}

func (this *AuthorizationHtpasswd) SetDefaults() error {
Expand All @@ -47,71 +36,23 @@ func (this *AuthorizationHtpasswd) SetDefaults() error {
})
},
noopSetDefault[AuthorizationHtpasswd]("entries"),
noopSetDefault[AuthorizationHtpasswd]("generateWithUserIfAbsentAndWarn"),
)
}

func (this *AuthorizationHtpasswd) Trim() error {
return trim(this,
noopTrim[AuthorizationHtpasswd]("file"),
noopTrim[AuthorizationHtpasswd]("entries"),
noopTrim[AuthorizationHtpasswd]("generateWithUserIfAbsentAndWarn"),
)
}

func (this *AuthorizationHtpasswd) Validate() (rErr error) {
if this.GenerateWithUserIfAbsentAndWarn && this.File.IsZero() && this.Entries.IsZero() {
fn, err := this.createDummyFileAndWarn()
if err != nil {
return err
}
if err := this.File.Set(fn); err != nil {
return err
}
}

return validate(this,
func(v *AuthorizationHtpasswd) (string, validator) { return "file", &v.File },
func(v *AuthorizationHtpasswd) (string, validator) { return "entries", &v.Entries },
noopValidate[AuthorizationHtpasswd]("generateWithUserIfAbsentAndWarn"),
)
}

func (this *AuthorizationHtpasswd) createDummyFileAndWarn() (fn string, rErr error) {
buf := make([]byte, 12)
if n, err := rand.Read(buf); err != nil {
return "", errors.System.Newf("cannot create demo password: %w", err)
} else if n != len(buf) {
return "", errors.System.Newf("cannot create demo password: not enough entries in random source")
}
pass := base58.Encode(buf)
hash, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
if err != nil {
return "", errors.System.Newf("cannot create demo password: %w", err)
}

_ = os.MkdirAll(filepath.Dir(DefaultAuthorizationHtpasswdFile), 0700)
f, err := os.OpenFile(DefaultAuthorizationHtpasswdFile, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
if os.IsExist(err) {
return DefaultAuthorizationHtpasswdFile, nil
}
if err != nil {
return "", errors.System.Newf("cannot create demo password in %q: %w", DefaultAuthorizationHtpasswdFile, err)
}
defer common.KeepCloseError(&rErr, f)

if _, err = fmt.Fprintf(f, "demo:%s\n", string(hash)); err != nil {
return "", errors.System.Newf("cannot create demo password in %q: %w", DefaultAuthorizationHtpasswdFile, err)
}

log.Warn("NOT CONFIGURED FOR PRODUCTION USE!!")
log.With("user", "demo").
With("password", pass).
Info("as this instance runs in dummy mode; a user for demonstration purposes was created - use this credentials to login to Bifröst - this message will never be shown again!")

return DefaultAuthorizationHtpasswdFile, nil
}

func (this *AuthorizationHtpasswd) UnmarshalYAML(node *yaml.Node) error {
return unmarshalYAML(this, node, func(target *AuthorizationHtpasswd, node *yaml.Node) error {
type raw AuthorizationHtpasswd
Expand All @@ -135,8 +76,7 @@ func (this AuthorizationHtpasswd) IsEqualTo(other any) bool {

func (this AuthorizationHtpasswd) isEqualTo(other *AuthorizationHtpasswd) bool {
return isEqual(&this.File, &other.File) &&
isEqual(&this.Entries, &other.Entries) &&
this.GenerateWithUserIfAbsentAndWarn == other.GenerateWithUserIfAbsentAndWarn
isEqual(&this.Entries, &other.Entries)
}

func (this AuthorizationHtpasswd) Types() []string {
Expand Down
12 changes: 11 additions & 1 deletion pkg/configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"github.com/engity-com/bifroest/pkg/sys"
)

var (
DefaultStartMessage = ""
)

type Configuration struct {
Ssh Ssh `yaml:"ssh"`

Expand All @@ -23,6 +27,8 @@ type Configuration struct {
Flows Flows `yaml:"flows"`

HouseKeeping HouseKeeping `yaml:"housekeeping"`

StartMessage string `yaml:"startMessage,omitempty"`
}

func (this *Configuration) SetDefaults() error {
Expand All @@ -31,6 +37,7 @@ func (this *Configuration) SetDefaults() error {
func(v *Configuration) (string, defaulter) { return "session", &v.Session },
func(v *Configuration) (string, defaulter) { return "flows", &v.Flows },
func(v *Configuration) (string, defaulter) { return "houseKeeping", &v.HouseKeeping },
fixedDefault("startMessage", func(v *Configuration) *string { return &v.StartMessage }, DefaultStartMessage),
)
}

Expand All @@ -40,6 +47,7 @@ func (this *Configuration) Trim() error {
func(v *Configuration) (string, trimmer) { return "session", &v.Session },
func(v *Configuration) (string, trimmer) { return "flows", &v.Flows },
func(v *Configuration) (string, trimmer) { return "houseKeeping", &v.HouseKeeping },
noopTrim[Configuration]("startMessage"),
)
}

Expand All @@ -50,6 +58,7 @@ func (this *Configuration) Validate() error {
func(v *Configuration) (string, validator) { return "flows", &v.Flows },
notEmptySliceValidate("flows", func(v *Configuration) *[]Flow { return (*[]Flow)(&v.Flows) }),
func(v *Configuration) (string, validator) { return "houseKeeping", &v.HouseKeeping },
noopValidate[Configuration]("startMessage"),
)
}

Expand Down Expand Up @@ -111,5 +120,6 @@ func (this Configuration) isEqualTo(other *Configuration) bool {
return isEqual(&this.Ssh, &other.Ssh) &&
isEqual(&this.Session, &other.Session) &&
isEqual(&this.Flows, &other.Flows) &&
isEqual(&this.HouseKeeping, &other.HouseKeeping)
isEqual(&this.HouseKeeping, &other.HouseKeeping) &&
this.StartMessage == other.StartMessage
}
10 changes: 10 additions & 0 deletions pkg/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"net"
"strings"
"sync"
"sync/atomic"
"syscall"
Expand Down Expand Up @@ -55,6 +56,15 @@ func (this *Service) Run(ctx context.Context) (rErr error) {
if ctx == nil {
ctx = context.Background()
}

if msg := this.Configuration.StartMessage; msg != "" {
for _, line := range strings.Split(msg, "\n") {
if line = strings.TrimSpace(line); line != "" {
log.Warn(line)
}
}
}

svc, err := this.prepare()
if err != nil {
return err
Expand Down

0 comments on commit f92cd1c

Please sign in to comment.