github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/security/choria/option.go (about) 1 // Copyright (c) 2022, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package choria 6 7 import ( 8 "crypto/ed25519" 9 "encoding/hex" 10 "fmt" 11 "os" 12 "path/filepath" 13 "runtime" 14 15 "github.com/choria-io/go-choria/config" 16 "github.com/choria-io/go-choria/inter" 17 "github.com/choria-io/go-choria/tlssetup" 18 "github.com/sirupsen/logrus" 19 ) 20 21 // Option is a function that can configure the Security Provider 22 type Option func(*ChoriaSecurity) error 23 24 // BuildInfoProvider provides info about the build 25 type BuildInfoProvider interface { 26 ClientIdentitySuffix() string 27 } 28 29 // WithChoriaConfig optionally configures the Security Provider from settings found in a typical Choria configuration 30 func WithChoriaConfig(c *config.Config) Option { 31 return func(s *ChoriaSecurity) error { 32 if c.Choria.ServerTokenFile != "" { 33 return fmt.Errorf("plugin.choria.security.server.token_file can not be set when the choria security provider is used") 34 } 35 36 if c.Choria.ServerTokenSeedFile != "" { 37 return fmt.Errorf("plugin.choria.security.server.seed_file can not be set when the choria security provider is used") 38 } 39 40 if c.Choria.ServerAnonTLS { 41 return fmt.Errorf("plugin.security.server_anon_tls can not be set when the choria security provider is used") 42 } 43 44 if c.Choria.ClientAnonTLS { 45 return fmt.Errorf("plugin.security.client_anon_tls can not be set when the choria security provider is used") 46 } 47 48 if c.Choria.RemoteSignerTokenSeedFile != "" { 49 return fmt.Errorf("plugin.choria.security.request_signer.seed_file can not be used when the choria security provider is used") 50 } 51 52 if c.Choria.RemoteSignerTokenFile != "" { 53 return fmt.Errorf("plugin.choria.security.request_signer.token_file can not be used when the choria security provider is used") 54 } 55 56 cfg := Config{ 57 TLSConfig: tlssetup.TLSConfig(c), 58 RemoteSignerURL: c.Choria.RemoteSignerURL, 59 SeedFile: filepath.FromSlash(c.Choria.ChoriaSecuritySeedFile), 60 TokenFile: filepath.FromSlash(c.Choria.ChoriaSecurityTokenFile), 61 CA: filepath.FromSlash(c.Choria.ChoriaSecurityCA), 62 Certificate: filepath.FromSlash(c.Choria.ChoriaSecurityCertificate), 63 Key: filepath.FromSlash(c.Choria.ChoriaSecurityKey), 64 DisableTLSVerify: c.DisableTLSVerify, 65 InitiatedByServer: c.InitiatedByServer, 66 SignedReplies: c.Choria.ChoriaSecuritySignReplies, 67 Issuers: make(map[string]ed25519.PublicKey), 68 } 69 70 for _, signer := range c.Choria.ChoriaSecurityTrustedSigners { 71 pk, err := hex.DecodeString(signer) 72 if err != nil { 73 return fmt.Errorf("invalid ed25519 public key: %v: %v", signer, err) 74 } 75 if len(pk) != ed25519.PublicKeySize { 76 return fmt.Errorf("invalid ed25519 public key size: %v: %v", signer, len(pk)) 77 } 78 79 cfg.TrustedTokenSigners = append(cfg.TrustedTokenSigners, pk) 80 } 81 82 for _, issuer := range c.Choria.IssuerNames { 83 name := fmt.Sprintf("plugin.security.issuer.%s.public", issuer) 84 pks := c.Option(name, "") 85 if pks == "" { 86 return fmt.Errorf("could not find option %s while adding issuer %s", name, issuer) 87 } 88 89 pk, err := hex.DecodeString(pks) 90 if err != nil { 91 return fmt.Errorf("invalid ed25519 public key in %s: %v", name, err) 92 } 93 94 cfg.Issuers[issuer] = pk 95 } 96 97 if c.InitiatedByServer { 98 cfg.Identity = c.Identity 99 } else { 100 userEnvVar := "USER" 101 if runtime.GOOS == "windows" { 102 userEnvVar = "USERNAME" 103 } 104 105 u, ok := os.LookupEnv(userEnvVar) 106 if !ok { 107 return fmt.Errorf("could not determine client identity, ensure %s environment variable is set", userEnvVar) 108 } 109 110 cfg.Identity = u 111 } 112 113 s.conf = &cfg 114 115 return nil 116 } 117 } 118 119 // WithTokenFile sets the path to the JWT token stored in a file 120 func WithTokenFile(f string) Option { 121 return func(s *ChoriaSecurity) error { 122 s.conf.TokenFile = f 123 return nil 124 } 125 } 126 127 // WithSeedFile sets the path to the ed25519 seed stored in a file 128 func WithSeedFile(f string) Option { 129 return func(s *ChoriaSecurity) error { 130 s.conf.SeedFile = f 131 return nil 132 } 133 } 134 135 // WithSigner configures a remote request signer 136 func WithSigner(signer inter.RequestSigner) Option { 137 return func(s *ChoriaSecurity) error { 138 s.conf.RemoteSigner = signer 139 140 return nil 141 } 142 } 143 144 // WithConfig optionally configures the Security Provider using its native configuration format 145 func WithConfig(c *Config) Option { 146 return func(s *ChoriaSecurity) error { 147 s.conf = c 148 149 if s.conf.TLSConfig == nil { 150 s.conf.TLSConfig = tlssetup.TLSConfig(nil) 151 } 152 153 return nil 154 } 155 } 156 157 // WithLog configures a logger for the Security Provider 158 func WithLog(l *logrus.Entry) Option { 159 return func(s *ChoriaSecurity) error { 160 s.log = l.WithFields(logrus.Fields{"security": "choria"}) 161 162 if s.conf.TLSConfig == nil { 163 s.conf.TLSConfig = tlssetup.TLSConfig(nil) 164 } 165 166 return nil 167 } 168 }