diff --git a/command/resource/client/grpc-config.go b/command/resource/client/grpc-config.go index e6aadff466..6fb205d351 100644 --- a/command/resource/client/grpc-config.go +++ b/command/resource/client/grpc-config.go @@ -38,6 +38,14 @@ const ( // GRPCCAPathEnvName defines an environment variable name which sets the // path to a directory of CA certs to use for talking to Consul gRPC over TLS. GRPCCAPathEnvName = "CONSUL_GRPC_CAPATH" + + // GRPCTokenEnvName defines an environment variable name which sets + // the GRPC token. + GRPCTokenEnvName = "CONSUL_GRPC_TOKEN" + + // GRPCTokenFileEnvName defines an environment variable name which sets + // the GRPC token file. + GRPCTokenFileEnvName = "CONSUL_GRPC_TOKEN_FILE" ) type GRPCConfig struct { @@ -67,6 +75,14 @@ type GRPCConfig struct { // CAPath is the optional path to a directory of CA certificates to use for // Consul communication, defaults to the system bundle if not specified. CAPath string + + // Token is used to provide a per-request ACL token + // which overrides the agent's default token. + Token string + + // TokenFile is a file containing the current token to use for this client. + // If provided it is read once at startup and never again. + TokenFile string } func GetDefaultGRPCConfig() *GRPCConfig { @@ -131,5 +147,13 @@ func loadEnvToDefaultConfig(config *GRPCConfig) (*GRPCConfig, error) { config.CAPath = caPath } + if token := os.Getenv(GRPCTokenEnvName); token != "" { + config.Token = token + } + + if tokenFile := os.Getenv(GRPCTokenFileEnvName); tokenFile != "" { + config.TokenFile = tokenFile + } + return config, nil } diff --git a/command/resource/client/grpc-config_test.go b/command/resource/client/grpc-config_test.go index 60a1e77bba..fa7a54b470 100644 --- a/command/resource/client/grpc-config_test.go +++ b/command/resource/client/grpc-config_test.go @@ -27,6 +27,8 @@ func TestLoadGRPCConfig(t *testing.T) { t.Setenv(GRPCClientKeyEnvName, "/path/to/client.key") t.Setenv(GRPCCAFileEnvName, "/path/to/ca.crt") t.Setenv(GRPCCAPathEnvName, "/path/to/cacerts") + t.Setenv(GRPCTokenEnvName, "token") + t.Setenv(GRPCTokenFileEnvName, "/path/to/token/file") // Load and validate the configuration config, err := LoadGRPCConfig(nil) @@ -39,6 +41,8 @@ func TestLoadGRPCConfig(t *testing.T) { KeyFile: "/path/to/client.key", CAFile: "/path/to/ca.crt", CAPath: "/path/to/cacerts", + Token: "token", + TokenFile: "/path/to/token/file", } assert.Equal(t, expectedConfig, config) }) diff --git a/command/resource/client/grpc-flags.go b/command/resource/client/grpc-flags.go index f3b7200253..92a15f2c9d 100644 --- a/command/resource/client/grpc-flags.go +++ b/command/resource/client/grpc-flags.go @@ -9,12 +9,14 @@ import ( ) type GRPCFlags struct { - address TValue[string] - grpcTLS TValue[bool] - certFile TValue[string] - keyFile TValue[string] - caFile TValue[string] - caPath TValue[string] + address TValue[string] + grpcTLS TValue[bool] + certFile TValue[string] + keyFile TValue[string] + caFile TValue[string] + caPath TValue[string] + token TValue[string] + tokenFile TValue[string] } // MergeFlagsIntoGRPCConfig merges flag values into grpc config @@ -34,6 +36,8 @@ func (f *GRPCFlags) MergeFlagsIntoGRPCConfig(c *GRPCConfig) { f.keyFile.Merge(&c.KeyFile) f.caFile.Merge(&c.CAFile) f.caPath.Merge(&c.CAPath) + f.token.Merge(&c.Token) + f.tokenFile.Merge(&c.TokenFile) } // merge the client flags into command line flags then parse command line flags @@ -60,5 +64,13 @@ func (f *GRPCFlags) ClientFlags() *flag.FlagSet { fs.Var(&f.caPath, "ca-path", "Path to a directory of CA certificates to use for TLS when communicating "+ "with Consul. This can also be specified via the CONSUL_CAPATH environment variable.") + fs.Var(&f.token, "token", + "ACL token to use in the request. This can also be specified via the "+ + "CONSUL_GRPC_TOKEN environment variable. If unspecified, the query will "+ + "default to the token of the Consul agent at the GRPC address.") + fs.Var(&f.tokenFile, "token-file", + "File containing the ACL token to use in the request instead of one specified "+ + "via the -token argument or CONSUL_GRPC_TOKEN environment variable. "+ + "This can also be specified via the CONSUL_GRPC_TOKEN_FILE environment variable.") return fs } diff --git a/command/resource/client/grpc-flags_test.go b/command/resource/client/grpc-flags_test.go index 9241a92c3e..fff95f0560 100644 --- a/command/resource/client/grpc-flags_test.go +++ b/command/resource/client/grpc-flags_test.go @@ -13,12 +13,14 @@ func TestMergeFlagsIntoGRPCConfig(t *testing.T) { t.Run("MergeFlagsIntoGRPCConfig", func(t *testing.T) { // Setup GRPCFlags with some flag values flags := &GRPCFlags{ - address: TValue[string]{v: stringPointer("https://example.com:8502")}, - grpcTLS: TValue[bool]{v: boolPointer(true)}, - certFile: TValue[string]{v: stringPointer("/path/to/client.crt")}, - keyFile: TValue[string]{v: stringPointer("/path/to/client.key")}, - caFile: TValue[string]{v: stringPointer("/path/to/ca.crt")}, - caPath: TValue[string]{v: stringPointer("/path/to/cacerts")}, + address: TValue[string]{v: stringPointer("https://example.com:8502")}, + grpcTLS: TValue[bool]{v: boolPointer(true)}, + certFile: TValue[string]{v: stringPointer("/path/to/client.crt")}, + keyFile: TValue[string]{v: stringPointer("/path/to/client.key")}, + caFile: TValue[string]{v: stringPointer("/path/to/ca.crt")}, + caPath: TValue[string]{v: stringPointer("/path/to/cacerts")}, + token: TValue[string]{v: stringPointer("token")}, + tokenFile: TValue[string]{v: stringPointer("/path/to/token/file")}, } // Setup GRPCConfig with some initial values @@ -30,6 +32,8 @@ func TestMergeFlagsIntoGRPCConfig(t *testing.T) { KeyFile: "/path/to/default/client.key", CAFile: "/path/to/default/ca.crt", CAPath: "/path/to/default/cacerts", + Token: "default-token", + TokenFile: "/path/to/default/token/file", } // Call MergeFlagsIntoGRPCConfig to merge flag values into the config @@ -44,6 +48,8 @@ func TestMergeFlagsIntoGRPCConfig(t *testing.T) { KeyFile: "/path/to/client.key", CAFile: "/path/to/ca.crt", CAPath: "/path/to/cacerts", + Token: "token", + TokenFile: "/path/to/token/file", } assert.Equal(t, expectedConfig, config)