Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ require (
github.com/sijms/go-ora/v2 v2.8.24
github.com/snowflakedb/gosnowflake v1.13.0
github.com/spf13/cobra v1.9.1
github.com/spiffe/aws-spiffe-workload-helper v0.0.1-rc.8
github.com/spiffe/go-spiffe/v2 v2.5.0
github.com/stretchr/testify v1.10.0
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb
Expand Down Expand Up @@ -296,6 +297,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.0 // indirect
github.com/aws/rolesanywhere-credential-helper v1.2.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.16 h1:BHEK2Q/7CMRMCb3nySi/w8UbIcP
github.com/aws/aws-sdk-go-v2/service/sts v1.33.16/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0 h1:EJsHUYgFBV7/N1YtL73lsfZODAOU+CnNSZfEAlqqQaA=
github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0/go.mod h1:AxKuXHc0zv2yYaeueUG7R3ONbcnQIuDj0bkdFmPVRzU=
github.com/aws/rolesanywhere-credential-helper v1.2.0 h1:eLqJvSznH8nJk48dwFc0raWOpbTGgBeNYH3Q8UQFVx4=
github.com/aws/rolesanywhere-credential-helper v1.2.0/go.mod h1:YRxmRrAaqbVVXPNH1gHT76nWaMGvpAziHAHw8UwKrpU=
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
Expand Down Expand Up @@ -2182,6 +2184,8 @@ github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/spiffe/aws-spiffe-workload-helper v0.0.1-rc.8 h1:KFHLQuNqUG4YZXo+QwMurqFxU5qWchFDCxYbl+uJz9w=
github.com/spiffe/aws-spiffe-workload-helper v0.0.1-rc.8/go.mod h1:xhhvkBenvvbuEEw9YR2HwGzUPv0sQiHd3wv8avhra+U=
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
3 changes: 3 additions & 0 deletions integrations/terraform/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.30.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.16 // indirect
github.com/aws/rolesanywhere-credential-helper v1.2.0 // indirect
github.com/aws/smithy-go v1.22.3 // indirect
github.com/aws/smithy-go/tracing/smithyoteltracing v1.0.4 // indirect
github.com/beevik/etree v1.5.0 // indirect
Expand Down Expand Up @@ -317,6 +318,7 @@ require (
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spiffe/aws-spiffe-workload-helper v0.0.1-rc.8 // indirect
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
Expand Down Expand Up @@ -375,6 +377,7 @@ require (
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
helm.sh/helm/v3 v3.17.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions integrations/terraform/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.16 h1:BHEK2Q/7CMRMCb3nySi/w8UbIcP
github.com/aws/aws-sdk-go-v2/service/sts v1.33.16/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0 h1:EJsHUYgFBV7/N1YtL73lsfZODAOU+CnNSZfEAlqqQaA=
github.com/aws/aws-sigv4-auth-cassandra-gocql-driver-plugin v1.1.0/go.mod h1:AxKuXHc0zv2yYaeueUG7R3ONbcnQIuDj0bkdFmPVRzU=
github.com/aws/rolesanywhere-credential-helper v1.2.0 h1:eLqJvSznH8nJk48dwFc0raWOpbTGgBeNYH3Q8UQFVx4=
github.com/aws/rolesanywhere-credential-helper v1.2.0/go.mod h1:YRxmRrAaqbVVXPNH1gHT76nWaMGvpAziHAHw8UwKrpU=
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/aws/smithy-go/tracing/smithyoteltracing v1.0.4 h1:Gx4ipHtKfaABSHAVo4Zjo2E4ClKzYqZ2NrPO0gy6qvY=
Expand Down Expand Up @@ -1158,6 +1160,8 @@ github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wx
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spiffe/aws-spiffe-workload-helper v0.0.1-rc.8 h1:KFHLQuNqUG4YZXo+QwMurqFxU5qWchFDCxYbl+uJz9w=
github.com/spiffe/aws-spiffe-workload-helper v0.0.1-rc.8/go.mod h1:xhhvkBenvvbuEEw9YR2HwGzUPv0sQiHd3wv8avhra+U=
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
172 changes: 172 additions & 0 deletions lib/tbot/cli/start_workload_identity_aws_ra.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package cli

import (
"fmt"
"log/slog"
"time"

"github.com/alecthomas/kingpin/v2"
"github.com/gravitational/trace"

"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/tbot/config"
)

// WorkloadIdentityAWSRACommand implements `tbot start workload-identity-aws-ra`
// and `tbot configure workload-identity-aws-ra`.
type WorkloadIdentityAWSRACommand struct {
*sharedStartArgs
*sharedDestinationArgs
*genericMutatorHandler

// NameSelector is the name of the workload identity to use.
// --workload-identity-name foo
NameSelector string
// LabelSelector is the labels of the workload identity to use.
// --workload-identity-labels x=y,z=a
LabelSelector string

// RoleARN is the ARN of the role to assume.
// Example: `arn:aws:iam::123456789012:role/example-role`
// Required.
RoleARN string
// ProfileARN is the ARN of the Roles Anywhere profile to use.
// Example: `arn:aws:rolesanywhere:us-east-1:123456789012:profile/0000000-0000-0000-0000-00000000000`
// Required.
ProfileARN string
// TrustAnchorARN is the ARN of the Roles Anywhere trust anchor to use.
// Example: `arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/0000000-0000-0000-0000-000000000000`
// Required.
TrustAnchorARN string
// Region is the AWS region to use.
// Example: `us-east-1`
// Must be set here or in the environment or AWS config using the
// `AWS_REGION` environment variable. If set here, this will override the
// environment or AWS config.
Region string

// SessionDuration is the duration of the resulting AWS session and
// credentials. This may be up to 12 hours. When unset, this defaults to
// 6 hours.
SessionDuration time.Duration
// SessionRenewalInterval is the interval at which the session should be
// renewed. This should be less than the session duration. When unset, this
// defaults to 1 hour.
SessionRenewalInterval time.Duration
}

// NewWorkloadIdentityAWSRACommand initializes the command and flags for the
// `workload-identity-aws-ra` output and returns a struct that will contain the parse
// result.
func NewWorkloadIdentityAWSRACommand(
parentCmd *kingpin.CmdClause, action MutatorAction, mode CommandMode,
) *WorkloadIdentityAWSRACommand {
cmd := parentCmd.Command(
"workload-identity-aws-roles-anywhere",
fmt.Sprintf(
"%s tbot with an output containing AWS credentials generated via AWS Roles Anywhere.",
mode,
),
)

c := &WorkloadIdentityAWSRACommand{}
c.sharedStartArgs = newSharedStartArgs(cmd)
c.sharedDestinationArgs = newSharedDestinationArgs(cmd)
c.genericMutatorHandler = newGenericMutatorHandler(cmd, c, action)

cmd.Flag(
"name-selector",
"The name of the workload identity to issue",
).StringVar(&c.NameSelector)
cmd.Flag(
"label-selector",
"A label-based selector for which workload identities to issue. Multiple labels can be provided using ','.",
).StringVar(&c.LabelSelector)
cmd.Flag(
"role-arn",
"The ARN of the role to assume.",
).Required().StringVar(&c.RoleARN)
cmd.Flag(
"profile-arn",
"The ARN of the Roles Anywhere profile to use.",
).Required().StringVar(&c.ProfileARN)
cmd.Flag(
"trust-anchor-arn",
"The ARN of the Roles Anywhere trust anchor to use.",
).Required().StringVar(&c.TrustAnchorARN)
cmd.Flag(
"region",
"The AWS region to use. If unset, value will be used from the AWS config or the AWS_REGION environment variable.",
).StringVar(&c.Region)

cmd.Flag(
"session-duration",
"The duration of the resulting AWS session and credentials. This may be up to 12 hours. When unset, this defaults to 6 hours.",
).DurationVar(&c.SessionDuration)
cmd.Flag(
"session-renewal-interval",
"How often the session should be renewed. This should be less than the session duration. When unset, this defaults to 1 hour.",
).DurationVar(&c.SessionRenewalInterval)

return c
}

// ApplyConfig applies the parsed flags to the bot configuration.
func (c *WorkloadIdentityAWSRACommand) ApplyConfig(cfg *config.BotConfig, l *slog.Logger) error {
if err := c.sharedStartArgs.ApplyConfig(cfg, l); err != nil {
return trace.Wrap(err)
}

dest, err := c.BuildDestination()
if err != nil {
return trace.Wrap(err)
}

svc := &config.WorkloadIdentityAWSRAService{
Destination: dest,
RoleARN: c.RoleARN,
ProfileARN: c.ProfileARN,
TrustAnchorARN: c.TrustAnchorARN,
Region: c.Region,
SessionDuration: c.SessionDuration,
SessionRenewalInterval: c.SessionRenewalInterval,
}

switch {
case c.NameSelector != "" && c.LabelSelector != "":
return trace.BadParameter("name-selector and label-selector flags are mutually exclusive")
case c.NameSelector != "":
svc.Selector.Name = c.NameSelector
case c.LabelSelector != "":
labels, err := client.ParseLabelSpec(c.LabelSelector)
if err != nil {
return trace.Wrap(err, "parsing --label-selector")
}
svc.Selector.Labels = map[string][]string{}
for k, v := range labels {
svc.Selector.Labels[k] = []string{v}
}
default:
return trace.BadParameter("name-selector or label-selector must be specified")
}

cfg.Services = append(cfg.Services, svc)

return nil
}
121 changes: 121 additions & 0 deletions lib/tbot/cli/start_workload_identity_aws_ra_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package cli

import (
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/gravitational/teleport/lib/tbot/config"
)

func TestWorkloadIdentityAWSRACommand(t *testing.T) {
testStartConfigureCommand(t, NewWorkloadIdentityAWSRACommand, []startConfigureTestCase{
{
name: "success",
args: []string{
"start",
"workload-identity-aws-roles-anywhere",
"--destination=/bar",
"--token=foo",
"--join-method=github",
"--proxy-server=example.com:443",
"--label-selector=*=*,foo=bar",
"--role-arn=arn:aws:iam::123456789012:role/example-role",
"--trust-anchor-arn=arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/0000000-0000-0000-0000-000000000000",
"--profile-arn=arn:aws:rolesanywhere:us-east-1:123456789012:profile/0000000-0000-0000-0000-00000000000",
"--region=us-east-1",
"--session-duration=2h",
"--session-renewal-interval=30m",
},
assertConfig: func(t *testing.T, cfg *config.BotConfig) {
require.Len(t, cfg.Services, 1)

svc := cfg.Services[0]
wis, ok := svc.(*config.WorkloadIdentityAWSRAService)
require.True(t, ok)

dir, ok := wis.Destination.(*config.DestinationDirectory)
require.True(t, ok)
require.Equal(t, "/bar", dir.Path)

require.Equal(t, map[string][]string{
"*": {"*"},
"foo": {"bar"},
}, wis.Selector.Labels)
require.Equal(t, "arn:aws:iam::123456789012:role/example-role", wis.RoleARN)
require.Equal(
t,
"arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/0000000-0000-0000-0000-000000000000",
wis.TrustAnchorARN,
)
require.Equal(
t,
"arn:aws:rolesanywhere:us-east-1:123456789012:profile/0000000-0000-0000-0000-00000000000",
wis.ProfileARN,
)
require.Equal(t, "us-east-1", wis.Region)

require.Equal(t, 2*time.Hour, wis.SessionDuration)
require.Equal(t, 30*time.Minute, wis.SessionRenewalInterval)
},
},
{
name: "success name selector",
args: []string{
"start",
"workload-identity-aws-roles-anywhere",
"--destination=/bar",
"--token=foo",
"--join-method=github",
"--proxy-server=example.com:443",
"--name-selector=jim",
"--role-arn=arn:aws:iam::123456789012:role/example-role",
"--trust-anchor-arn=arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/0000000-0000-0000-0000-000000000000",
"--profile-arn=arn:aws:rolesanywhere:us-east-1:123456789012:profile/0000000-0000-0000-0000-00000000000",
"--region=us-east-1",
},
assertConfig: func(t *testing.T, cfg *config.BotConfig) {
require.Len(t, cfg.Services, 1)

svc := cfg.Services[0]
wis, ok := svc.(*config.WorkloadIdentityAWSRAService)
require.True(t, ok)

dir, ok := wis.Destination.(*config.DestinationDirectory)
require.True(t, ok)
require.Equal(t, "/bar", dir.Path)

require.Equal(t, "jim", wis.Selector.Name)
require.Equal(t, "arn:aws:iam::123456789012:role/example-role", wis.RoleARN)
require.Equal(
t,
"arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/0000000-0000-0000-0000-000000000000",
wis.TrustAnchorARN,
)
require.Equal(
t,
"arn:aws:rolesanywhere:us-east-1:123456789012:profile/0000000-0000-0000-0000-00000000000",
wis.ProfileARN,
)
require.Equal(t, "us-east-1", wis.Region)
},
},
})
}
6 changes: 6 additions & 0 deletions lib/tbot/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,12 @@ func (o *ServiceConfigs) UnmarshalYAML(node *yaml.Node) error {
return trace.Wrap(err)
}
out = append(out, v)
case WorkloadIdentityAWSRAType:
v := &WorkloadIdentityAWSRAService{}
if err := node.Decode(v); err != nil {
return trace.Wrap(err)
}
out = append(out, v)
default:
return trace.BadParameter("unrecognized service type (%s)", header.Type)
}
Expand Down
Loading
Loading