diff --git a/lib/auth/machineid/workloadidentityv1/decision_test.go b/lib/auth/machineid/workloadidentityv1/decision_test.go index bf18594416609..ef15ef7b09777 100644 --- a/lib/auth/machineid/workloadidentityv1/decision_test.go +++ b/lib/auth/machineid/workloadidentityv1/decision_test.go @@ -45,6 +45,23 @@ func Test_getFieldStringValue(t *testing.T) { want: "jeff", requireErr: require.NoError, }, + { + // This test ensures that the proto name (e.g service_account) is + // used instead of the Go name (e.g serviceAccount). + name: "underscored", + in: &workloadidentityv1pb.Attrs{ + Join: &workloadidentityv1pb.JoinAttrs{ + Kubernetes: &workloadidentityv1pb.JoinAttrsKubernetes{ + ServiceAccount: &workloadidentityv1pb.JoinAttrsKubernetesServiceAccount{ + Namespace: "default", + }, + }, + }, + }, + attr: "join.kubernetes.service_account.namespace", + want: "default", + requireErr: require.NoError, + }, { name: "bool", in: &workloadidentityv1pb.Attrs{ diff --git a/lib/auth/machineid/workloadidentityv1/issuer_service.go b/lib/auth/machineid/workloadidentityv1/issuer_service.go index 7b498f7f16d9a..ee2a9b6d3f802 100644 --- a/lib/auth/machineid/workloadidentityv1/issuer_service.go +++ b/lib/auth/machineid/workloadidentityv1/issuer_service.go @@ -135,6 +135,7 @@ func (s *IssuanceService) deriveAttrs( BotName: authzCtx.Identity.GetIdentity().BotName, Labels: authzCtx.User.GetAllLabels(), }, + Join: authzCtx.Identity.GetIdentity().JoinAttributes, } return attrs, nil diff --git a/lib/tlsca/ca_test.go b/lib/tlsca/ca_test.go index 022facef5d0cf..50295f1e7bcf9 100644 --- a/lib/tlsca/ca_test.go +++ b/lib/tlsca/ca_test.go @@ -34,8 +34,10 @@ import ( "github.com/jonboulle/clockwork" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" "github.com/gravitational/teleport" + workloadidentityv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1" apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/api/utils/keys" "github.com/gravitational/teleport/lib/cryptosuites" @@ -154,6 +156,58 @@ func TestRenewableIdentity(t *testing.T) { require.True(t, parsed.Renewable) } +func TestJoinAttributes(t *testing.T) { + t.Parallel() + + clock := clockwork.NewFakeClock() + expires := clock.Now().Add(1 * time.Hour) + + ca, err := FromKeys([]byte(fixtures.TLSCACertPEM), []byte(fixtures.TLSCAKeyPEM)) + require.NoError(t, err) + + privateKey, err := cryptosuites.GenerateKeyWithAlgorithm(cryptosuites.ECDSAP256) + require.NoError(t, err) + + identity := Identity{ + Username: "bot-bernard", + Groups: []string{"bot-bernard"}, + BotName: "bernard", + BotInstanceID: "1234-5678", + Expires: expires, + JoinAttributes: &workloadidentityv1pb.JoinAttrs{ + Kubernetes: &workloadidentityv1pb.JoinAttrsKubernetes{ + ServiceAccount: &workloadidentityv1pb.JoinAttrsKubernetesServiceAccount{ + Namespace: "default", + Name: "foo", + }, + Pod: &workloadidentityv1pb.JoinAttrsKubernetesPod{ + Name: "bar", + }, + }, + }, + } + + subj, err := identity.Subject() + require.NoError(t, err) + require.NotNil(t, subj) + + certBytes, err := ca.GenerateCertificate(CertificateRequest{ + Clock: clock, + PublicKey: privateKey.Public(), + Subject: subj, + NotAfter: expires, + }) + require.NoError(t, err) + + cert, err := ParseCertificatePEM(certBytes) + require.NoError(t, err) + + parsed, err := FromSubject(cert.Subject, expires) + require.NoError(t, err) + require.NotNil(t, parsed) + require.Empty(t, cmp.Diff(parsed, &identity, protocmp.Transform())) +} + // TestKubeExtensions test ASN1 subject kubernetes extensions func TestKubeExtensions(t *testing.T) { clock := clockwork.NewFakeClock()