Skip to content

Commit

Permalink
Add daemon mode flag
Browse files Browse the repository at this point in the history
Signed-off-by: Faisal Memon <fymemon@yahoo.com>
  • Loading branch information
faisal-memon committed Jul 1, 2024
1 parent fc54f46 commit e6e9234
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 43 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The configuration file is an [HCL](https://github.com/hashicorp/hcl) formatted f
| `cmd` | The path to the process to launch. | `"ghostunnel"` |
| `cmd_args` | The arguments of the process to launch. | `"server --listen localhost:8002 --target localhost:8001--keystore certs/svid_key.pem --cacert certs/svid_bundle.pem --allow-uri-san spiffe://example.org/Database"` |
| `cert_dir` | Directory name to store the fetched certificates. This directory must be created previously. | `"certs"` |
| `exit_when_ready` | Fetch x509 certificate and then exit(0) | `true` |
| `daemon_mode` | Toggle running as a daemon, keeping X.509 and JWT up to date; or just fetch X.509 and JWT and exit 0 | `true` |
| `add_intermediates_to_bundle` | Add intermediate certificates into Bundle file instead of SVID file. | `true` |
| `renew_signal` | The signal that the process to be launched expects to reload the certificates. It is not supported on Windows. | `"SIGUSR1"` |
| `svid_file_name` | File name to be used to store the X.509 SVID public certificate in PEM format. | `"svid.pem"` |
Expand Down
50 changes: 37 additions & 13 deletions cmd/spiffe-helper/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ type Config struct {
CmdArgsDeprecated string `hcl:"cmdArgs"`
CertDir string `hcl:"cert_dir"`
CertDirDeprecated string `hcl:"certDir"`
ExitWhenReady bool `hcl:"exit_when_ready"`
IncludeFederatedDomains bool `hcl:"include_federated_domains"`
RenewSignal string `hcl:"renew_signal"`
RenewSignalDeprecated string `hcl:"renewSignal"`
DaemonMode *bool `hcl:"daemon_mode"`

// x509 configuration
SVIDFileName string `hcl:"svid_file_name"`
Expand All @@ -48,26 +48,26 @@ type JWTConfig struct {

// ParseConfig parses the given HCL file into a Config struct
func ParseConfig(file string) (*Config, error) {
sidecarConfig := new(Config)

// Read HCL file
dat, err := os.ReadFile(file)
if err != nil {
return nil, err
}

// Parse HCL
if err := hcl.Decode(sidecarConfig, string(dat)); err != nil {
config := new(Config)
if err := hcl.Decode(config, string(dat)); err != nil {
return nil, err
}

return sidecarConfig, nil
return config, nil
}

func ValidateConfig(c *Config, exitWhenReady bool, log logrus.FieldLogger) error {
func ValidateConfig(c *Config, disableDaemonMode bool, log logrus.FieldLogger) error {
if err := validateOSConfig(c); err != nil {
return err
}

if c.AgentAddressDeprecated != "" {
if c.AgentAddress != "" {
return errors.New("use of agent_address and agentAddress found, use only agent_address")
Expand Down Expand Up @@ -140,16 +140,26 @@ func ValidateConfig(c *Config, exitWhenReady bool, log logrus.FieldLogger) error
}
}

c.ExitWhenReady = c.ExitWhenReady || exitWhenReady
x509Enabled, err := validateX509Config(c)
if err != nil {
return err
}

jwtBundleEnabled, jwtSVIDsEnabled := validateJWTConfig(c)

x509EmptyCount := countEmpty(c.SVIDFileName, c.SVIDBundleFileName, c.SVIDKeyFileName)
jwtBundleEmptyCount := countEmpty(c.SVIDBundleFileName)
if x509EmptyCount == 3 && len(c.JWTSVIDs) == 0 && jwtBundleEmptyCount == 1 {
if !x509Enabled && !jwtBundleEnabled && !jwtSVIDsEnabled {
return errors.New("at least one of the sets ('svid_file_name', 'svid_key_file_name', 'svid_bundle_file_name'), 'jwt_svids', or 'jwt_bundle_file_name' must be fully specified")
}

if x509EmptyCount != 0 && x509EmptyCount != 3 {
return errors.New("all or none of 'svid_file_name', 'svid_key_file_name', 'svid_bundle_file_name' must be specified")
var daemonMode bool
if disableDaemonMode {
// If daemon mode is disabled by CLI this takes precedence
daemonMode = false
c.DaemonMode = &daemonMode
} else if c.DaemonMode == nil {
// If daemon mode is not set, then default to true
daemonMode = true
c.DaemonMode = &daemonMode
}

return nil
Expand All @@ -162,7 +172,6 @@ func NewSidecarConfig(config *Config, log logrus.FieldLogger) *sidecar.Config {
Cmd: config.Cmd,
CmdArgs: config.CmdArgs,
CertDir: config.CertDir,
ExitWhenReady: config.ExitWhenReady,
IncludeFederatedDomains: config.IncludeFederatedDomains,
JWTBundleFilename: config.JWTBundleFilename,
Log: log,
Expand All @@ -182,6 +191,21 @@ func NewSidecarConfig(config *Config, log logrus.FieldLogger) *sidecar.Config {
return sidecarConfig
}

func validateX509Config(c *Config) (bool, error) {
x509EmptyCount := countEmpty(c.SVIDFileName, c.SVIDBundleFileName, c.SVIDKeyFileName)
if x509EmptyCount != 0 && x509EmptyCount != 3 {
return false, errors.New("all or none of 'svid_file_name', 'svid_key_file_name', 'svid_bundle_file_name' must be specified")
}

return x509EmptyCount == 0, nil
}

func validateJWTConfig(c *Config) (bool, bool) {
jwtBundleEmptyCount := countEmpty(c.SVIDBundleFileName)

return jwtBundleEmptyCount == 0, len(c.JWTSVIDs) > 0
}

func getWarning(s1 string, s2 string) string {
return s1 + " will be deprecated, should be used as " + s2
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/spiffe-helper/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ func TestNewSidecarConfig(t *testing.T) {
assert.Equal(t, "", sidecarConfig.RenewSignal)
}

func TestExitOnWaitFlag(t *testing.T) {
func TestDisableDaemonModeFlag(t *testing.T) {
config := &Config{
SVIDFileName: "cert.pem",
SVIDKeyFileName: "key.pem",
Expand All @@ -397,7 +397,8 @@ func TestExitOnWaitFlag(t *testing.T) {
log, _ := test.NewNullLogger()
err := ValidateConfig(config, true, log)
require.NoError(t, err)
assert.Equal(t, config.ExitWhenReady, true)
require.NotNil(t, config.DaemonMode)
assert.Equal(t, *config.DaemonMode, false)
}

type shortEntry struct {
Expand Down
30 changes: 17 additions & 13 deletions cmd/spiffe-helper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,43 @@ import (
)

func main() {
// 0. Load configuration
// 1. Create Sidecar
// 2. Run Sidecar's Daemon

configFile := flag.String("config", "helper.conf", "<configFile> Configuration file path")
exitWhenReady := flag.Bool("exitWhenReady", false, "Exit once the requested objects are retrieved")
disableDaemonMode := flag.Bool("disable_daemon_mode", false, "Exit once the requested objects are retrieved")
flag.Parse()

log := logrus.WithField("system", "spiffe-helper")
log.Infof("Using configuration file: %q\n", *configFile)
log.Infof("Using configuration file: %q", *configFile)

if err := startSidecar(*configFile, *exitWhenReady, log); err != nil {
log.WithError(err).Error("Exiting due this error")
if err := startSidecar(*configFile, *disableDaemonMode, log); err != nil {
log.WithError(err).Errorf("Error starting spiffe-helper")
os.Exit(1)
}

log.Infof("Exiting")
os.Exit(0)
}

func startSidecar(configPath string, exitWhenReady bool, log logrus.FieldLogger) error {
func startSidecar(configFile string, disableDaemonMode bool, log logrus.FieldLogger) error {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()

hclConfig, err := config.ParseConfig(configPath)
hclConfig, err := config.ParseConfig(configFile)
if err != nil {
return fmt.Errorf("failed to parse %q: %w", configPath, err)
return fmt.Errorf("Failed to parse %q: %w", configFile, err)
}
if err := config.ValidateConfig(hclConfig, exitWhenReady, log); err != nil {
return fmt.Errorf("invalid configuration: %w", err)

if err := config.ValidateConfig(hclConfig, disableDaemonMode, log); err != nil {
return fmt.Errorf("Invalid configuration: %w", err)
}

sidecarConfig := config.NewSidecarConfig(hclConfig, log)
spiffeSidecar := sidecar.New(sidecarConfig)

if !*hclConfig.DaemonMode {
log.Info("Daemon mode disabled")
return spiffeSidecar.Run(ctx)
}

log.Info("Launching daemon")
return spiffeSidecar.RunDaemon(ctx)
}
56 changes: 56 additions & 0 deletions examples/k8s/helper.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: spiffe-helper
---
apiVersion: v1
kind: ConfigMap
metadata:
name: spiffe-helper
data:
helper.conf: |
cmd = ""
cmd_args = ""
cert_dir = ""
renew_signal = ""
svid_file_name = "tls.crt"
svid_key_file_name = "tls.key"
svid_bundle_file_name = "ca.pem"
jwt_bundle_file_name = "cert.jwt"
daemon_mode = false
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spiffe-helper
labels:
app: spiffe-helper
spec:
selector:
matchLabels:
app: spiffe-helper
template:
metadata:
labels:
app: spiffe-helper
spiffe.io/spiffe-id: "true"
spec:
serviceAccountName: spiffe-helper
containers:
- name: spiffe-helper
image: ghcr.io/spiffe/spiffe-helper:devel
args: ["-config", "config/helper.conf"]
volumeMounts:
- name: spire-agent-socket
mountPath: /tmp/spire-agent/public/
readOnly: true
- name: helper-config
mountPath: /config
volumes:
- name: spire-agent-socket
hostPath:
path: /run/spire/agent-sockets
type: Directory
- name: helper-config
configMap:
name: spiffe-helper
14 changes: 14 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,25 @@ require (
github.com/stretchr/testify v1.9.0
golang.org/x/sys v0.21.0
google.golang.org/grpc v1.64.0
k8s.io/apimachinery v0.30.1
k8s.io/client-go v0.30.1
)

require (
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)

require (
Expand Down
Loading

0 comments on commit e6e9234

Please sign in to comment.