pkg/cmd/serviceaccount/phases/create/federatedidentitycredential.go (83 lines of code) (raw):

package phases import ( "context" "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/pkg/errors" "monis.app/mlog" "github.com/Azure/azure-workload-identity/pkg/cloud" "github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/options" "github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/phases/workflow" "github.com/Azure/azure-workload-identity/pkg/cmd/serviceaccount/util" "github.com/Azure/azure-workload-identity/pkg/webhook" ) const ( federatedIdentityPhaseName = "federated-identity" ) type federatedIdentityPhase struct { } // NewFederatedIdentityPhase creates a new phase to create federated identity credential. func NewFederatedIdentityPhase() workflow.Phase { p := &federatedIdentityPhase{} return workflow.Phase{ Name: federatedIdentityPhaseName, Aliases: []string{"fi"}, Description: "Create federated identity credential between the AAD application and the Kubernetes service account", PreRun: p.prerun, Run: p.run, Flags: []string{ options.ServiceAccountNamespace.Flag, options.ServiceAccountName.Flag, options.ServiceAccountIssuerURL.Flag, options.AADApplicationName.Flag, options.AADApplicationObjectID.Flag, }, } } func (p *federatedIdentityPhase) prerun(data workflow.RunData) error { createData, ok := data.(CreateData) if !ok { return errors.Errorf("invalid data type %T", data) } if createData.ServiceAccountNamespace() == "" { return options.FlagIsRequiredError(options.ServiceAccountNamespace.Flag) } if createData.ServiceAccountName() == "" { return options.FlagIsRequiredError(options.ServiceAccountName.Flag) } if createData.ServiceAccountIssuerURL() == "" { return options.FlagIsRequiredError(options.ServiceAccountIssuerURL.Flag) } return nil } func (p *federatedIdentityPhase) run(ctx context.Context, data workflow.RunData) error { createData := data.(CreateData) serviceAccountNamespace, serviceAccountName := createData.ServiceAccountNamespace(), createData.ServiceAccountName() subject := util.GetFederatedCredentialSubject(serviceAccountNamespace, serviceAccountName) name := util.GetFederatedCredentialName(serviceAccountNamespace, serviceAccountName, createData.ServiceAccountIssuerURL()) description := fmt.Sprintf("Federated Service Account for %s/%s", serviceAccountNamespace, serviceAccountName) audiences := []string{webhook.DefaultAudience} objectID := createData.AADApplicationObjectID() fic := models.NewFederatedIdentityCredential() fic.SetAudiences(audiences) fic.SetDescription(to.Ptr(description)) fic.SetIssuer(to.Ptr(createData.ServiceAccountIssuerURL())) fic.SetSubject(to.Ptr(subject)) fic.SetName(to.Ptr(name)) err := createData.AzureClient().AddFederatedCredential(ctx, objectID, fic) if err != nil { if cloud.IsFederatedCredentialAlreadyExists(err) { mlog.WithValues( "objectID", objectID, "subject", subject, ).WithName(federatedIdentityPhaseName).Warning("federated credential has been previously created") } else { return errors.Wrap(err, "failed to add federated credential") } } mlog.WithValues( "objectID", objectID, "subject", subject, ).WithName(federatedIdentityPhaseName).Info("added federated credential") return nil }