From 1c960af72d05df25cec4db4f6918d62d3ceef1aa Mon Sep 17 00:00:00 2001 From: Matt Brock Date: Sat, 12 Oct 2024 19:19:31 -0500 Subject: [PATCH 1/2] Initial command to create the managed identity and role --- go.mod | 1 + lib/config/configuration.go | 15 +++ ..._graph_aws_sync.go => accessgraph_sync.go} | 0 ..._sync_test.go => accessgraph_sync_test.go} | 0 .../azureoidc/accessgraph_sync.go | 107 ++++++++++++++++++ tool/teleport/common/integration_configure.go | 6 + tool/teleport/common/teleport.go | 18 ++- 7 files changed, 142 insertions(+), 5 deletions(-) rename lib/integrations/awsoidc/{access_graph_aws_sync.go => accessgraph_sync.go} (100%) rename lib/integrations/awsoidc/{access_graph_aws_sync_test.go => accessgraph_sync_test.go} (100%) create mode 100644 lib/integrations/azureoidc/accessgraph_sync.go diff --git a/go.mod b/go.mod index 8c464ff082e65..42637613208f9 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( connectrpc.com/connect v1.17.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.1.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 diff --git a/lib/config/configuration.go b/lib/config/configuration.go index 929bb757a85ca..be6c89d0cbd99 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -251,6 +251,8 @@ type CommandLineFlags struct { // `teleport integration configure access-graph aws-iam` command IntegrationConfAccessGraphAWSSyncArguments IntegrationConfAccessGraphAWSSync + IntegrationConfAccessGraphAzureSyncArguments IntegrationConfAccessGraphAzureSync + // IntegrationConfAzureOIDCArguments contains the arguments of // `teleport integration configure azure-oidc` command IntegrationConfAzureOIDCArguments IntegrationConfAzureOIDC @@ -283,6 +285,19 @@ type IntegrationConfAccessGraphAWSSync struct { AutoConfirm bool } +// IntegrationConfAccessGraphAzureSync contains the arguments of +// `teleport integration configure access-graph azure` command. +type IntegrationConfAccessGraphAzureSync struct { + // ManagedIdentity is the principal performing the discovery + ManagedIdentity string + // Role is the Azure Role associated with the integration + Role string + // SubscriptionID is the Azure subscription containing resources for sync + SubscriptionID string + // AutoConfirm skips user confirmation of the operation plan if true. + AutoConfirm bool +} + // IntegrationConfAzureOIDC contains the arguments of // `teleport integration configure azure-oidc` command type IntegrationConfAzureOIDC struct { diff --git a/lib/integrations/awsoidc/access_graph_aws_sync.go b/lib/integrations/awsoidc/accessgraph_sync.go similarity index 100% rename from lib/integrations/awsoidc/access_graph_aws_sync.go rename to lib/integrations/awsoidc/accessgraph_sync.go diff --git a/lib/integrations/awsoidc/access_graph_aws_sync_test.go b/lib/integrations/awsoidc/accessgraph_sync_test.go similarity index 100% rename from lib/integrations/awsoidc/access_graph_aws_sync_test.go rename to lib/integrations/awsoidc/accessgraph_sync_test.go diff --git a/lib/integrations/azureoidc/accessgraph_sync.go b/lib/integrations/azureoidc/accessgraph_sync.go new file mode 100644 index 0000000000000..e4411710ecafc --- /dev/null +++ b/lib/integrations/azureoidc/accessgraph_sync.go @@ -0,0 +1,107 @@ +package azureoidc + +import ( + "context" + "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi" + "github.com/google/uuid" + "github.com/gravitational/teleport/lib/cloud/provisioning" + "github.com/gravitational/teleport/lib/config" + "github.com/gravitational/trace" + "log/slog" + "os" +) + +func newManagedIdAction(cred *azidentity.DefaultAzureCredential, subId string, name string) (*provisioning.Action, error) { + runnerFn := func(ctx context.Context) error { + // Create the managed identity + userIdCli, err := armmsi.NewUserAssignedIdentitiesClient(subId, cred, nil) + if err != nil { + return trace.Wrap(fmt.Errorf("could not create managed identity client: %v", err)) + } + id := armmsi.Identity{} + mgdIdRes, err := userIdCli.CreateOrUpdate(ctx, "", name, id, nil) + if err != nil { + return trace.Wrap(fmt.Errorf("could not create managed identity: %v", err)) + } + slog.InfoContext(ctx, fmt.Sprintf( + "Managed identity created, Name: %s, ID: %s", *mgdIdRes.Name, *mgdIdRes.ID)) + + // Create the role + roleDefCli, err := armauthorization.NewRoleDefinitionsClient(cred, nil) + if err != nil { + return trace.Wrap(fmt.Errorf("failed to create role definitions client: %v", err)) + } + roleDefId := uuid.New().String() + customRole := "CustomRole" + // TODO(mbrock): Determine scope + scope := "" + roleDefinition := armauthorization.RoleDefinition{ + Name: &roleDefId, + Properties: &armauthorization.RoleDefinitionProperties{ + RoleName: &name, + RoleType: &customRole, + Permissions: []*armauthorization.Permission{ + // TODO(mbrock): Add permissions + }, + AssignableScopes: []*string{&scope}, // Scope must be provided + }, + } + roleRes, err := roleDefCli.CreateOrUpdate(ctx, scope, roleDefId, roleDefinition, nil) + if err != nil { + return trace.Wrap(fmt.Errorf("failed to create custom role: %v", err)) + } + + // Assign the role to the managed identity + roleAssignCli, err := armauthorization.NewRoleAssignmentsClient(subId, cred, nil) + if err != nil { + return fmt.Errorf("failed to create role assignments client: %v", err) + } + assignName := uuid.New().String() + if err != nil { + return trace.Wrap(fmt.Errorf("failed to create role assignments client: %v", err)) + } + roleAssignParams := armauthorization.RoleAssignmentCreateParameters{ + Properties: &armauthorization.RoleAssignmentProperties{ + PrincipalID: mgdIdRes.ID, + RoleDefinitionID: roleRes.ID, + }, + } + _, err = roleAssignCli.Create(ctx, scope, assignName, roleAssignParams, nil) + if err != nil { + return fmt.Errorf("failed to create role assignment: %v", err) + } + + return nil + } + cfg := provisioning.ActionConfig{ + Name: "NewSyncManagedId", + Summary: "Creates a new Azure managed ID for the discovery service to use", + RunnerFn: runnerFn, + } + return provisioning.NewAction(cfg) +} + +// ConfigureAccessGraphSyncAzure sets up the managed identity and role required for Teleport to be able to pull +// AWS resources into Teleport. +func ConfigureAccessGraphSyncAzure(ctx context.Context, params config.IntegrationConfAccessGraphAzureSync) error { + cred, err := azidentity.NewDefaultAzureCredential(nil) + if err != nil { + return trace.Wrap(err) + } + managedIdAction, err := newManagedIdAction(cred, params.SubscriptionID, params.ManagedIdentity) + if err != nil { + return trace.Wrap(err) + } + opCfg := provisioning.OperationConfig{ + Name: "access-graph-azure-sync", + Actions: []provisioning.Action{ + *managedIdAction, + }, + AutoConfirm: params.AutoConfirm, + Output: os.Stdout, + } + return trace.Wrap(provisioning.Run(ctx, opCfg)) +} diff --git a/tool/teleport/common/integration_configure.go b/tool/teleport/common/integration_configure.go index 97f531910e45e..13c9e32980c7e 100644 --- a/tool/teleport/common/integration_configure.go +++ b/tool/teleport/common/integration_configure.go @@ -241,6 +241,12 @@ func onIntegrationConfAccessGraphAWSSync(ctx context.Context, params config.Inte return trace.Wrap(awsoidc.ConfigureAccessGraphSyncIAM(ctx, clt, confReq)) } +func onIntegrationConfAccessGraphAzureSync(ctx context.Context, params config.IntegrationConfAccessGraphAzureSync) error { + // Ensure we print output to the user. LogLevel at this point was set to Error. + utils.InitLogger(utils.LoggingForDaemon, slog.LevelInfo) + return trace.Wrap(azureoidc.ConfigureAccessGraphSyncAzure(ctx, params)) +} + func onIntegrationConfAzureOIDCCmd(ctx context.Context, params config.IntegrationConfAzureOIDC) error { // Ensure we print output to the user. LogLevel at this point was set to Error. utils.InitLogger(utils.LoggingForDaemon, slog.LevelInfo) diff --git a/tool/teleport/common/teleport.go b/tool/teleport/common/teleport.go index 8318fcf68a45f..bf900ee78cc01 100644 --- a/tool/teleport/common/teleport.go +++ b/tool/teleport/common/teleport.go @@ -508,10 +508,16 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con integrationConfEKSCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfEKSIAMArguments.AutoConfirm) integrationConfAccessGraphCmd := integrationConfigureCmd.Command("access-graph", "Manages Access Graph configuration.") - integrationConfTAGSyncCmd := integrationConfAccessGraphCmd.Command("aws-iam", "Adds required IAM permissions for syncing data into Access Graph service.") - integrationConfTAGSyncCmd.Flag("role", "The AWS Role used by the AWS OIDC Integration.").Required().StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.Role) - integrationConfTAGSyncCmd.Flag("aws-account-id", "The AWS account ID.").StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AccountID) - integrationConfTAGSyncCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AutoConfirm) + integrationConfAccessGraphAWSSyncCmd := integrationConfAccessGraphCmd.Command("aws-iam", "Adds required IAM permissions for syncing data into Access Graph service.") + integrationConfAccessGraphAWSSyncCmd.Flag("role", "The AWS Role used by the AWS OIDC Integration.").Required().StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.Role) + integrationConfAccessGraphAWSSyncCmd.Flag("aws-account-id", "The AWS account ID.").StringVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AccountID) + integrationConfAccessGraphAWSSyncCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfAccessGraphAWSSyncArguments.AutoConfirm) + + integrationConfAccessGraphAzureSyncCmd := integrationConfAccessGraphCmd.Command("azure", "Creates/updates permissions for syncing data into Access Graph service.") + integrationConfAccessGraphAzureSyncCmd.Flag("managed-identity", "The managed identity runs the discovery service.").Required() + integrationConfAccessGraphAzureSyncCmd.Flag("role", "The role attached to the managed identity with the discovery permissions.").Required() + integrationConfAccessGraphAzureSyncCmd.Flag("subscription-id", "The subscription ID in which to discovery resources.") + integrationConfAccessGraphAzureSyncCmd.Flag("confirm", "Apply changes without confirmation prompt.") integrationConfAWSOIDCIdPCmd := integrationConfigureCmd.Command("awsoidc-idp", "Creates an IAM IdP (OIDC) in your AWS account to allow the AWS OIDC Integration to access AWS APIs.") integrationConfAWSOIDCIdPCmd.Flag("cluster", "Teleport Cluster name.").Required().StringVar(&ccf. @@ -721,8 +727,10 @@ Examples: err = onIntegrationConfListDatabasesIAM(ctx, ccf.IntegrationConfListDatabasesIAMArguments) case integrationConfExternalAuditCmd.FullCommand(): err = onIntegrationConfExternalAuditCmd(ctx, ccf.IntegrationConfExternalAuditStorageArguments) - case integrationConfTAGSyncCmd.FullCommand(): + case integrationConfAccessGraphAWSSyncCmd.FullCommand(): err = onIntegrationConfAccessGraphAWSSync(ctx, ccf.IntegrationConfAccessGraphAWSSyncArguments) + case integrationConfAccessGraphAzureSyncCmd.FullCommand(): + err = onIntegrationConfAccessGraphAzureSync(ctx, ccf.IntegrationConfAccessGraphAzureSyncArguments) case integrationConfAzureOIDCCmd.FullCommand(): err = onIntegrationConfAzureOIDCCmd(ctx, ccf.IntegrationConfAzureOIDCArguments) case integrationSAMLIdPGCPWorkforce.FullCommand(): From 142264d3f5f73476f0de7ceca5a161c8063a92af Mon Sep 17 00:00:00 2001 From: Matt Brock Date: Mon, 23 Dec 2024 11:23:12 -0600 Subject: [PATCH 2/2] Go.mod conflicts --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 42637613208f9..4de1578b98ec8 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( connectrpc.com/connect v1.17.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization v1.0.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.1.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 diff --git a/go.sum b/go.sum index 354d9459e95f9..9de3414e778af 100644 --- a/go.sum +++ b/go.sum @@ -668,6 +668,8 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLC github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization v1.0.0 h1:qtRcg5Y7jNJ4jEzPq4GpWLfTspHdNe2ZK6LjwGcjgmU= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization v1.0.0/go.mod h1:lPneRe3TwsoDRKY4O6YDLXHhEWrD+TIRa8XrV/3/fqw= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.1.0 h1:zDeQI/PaWztI2tcrGO/9RIMey9NvqYbnyttf/0P3QWM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.1.0/go.mod h1:zflC9v4VfViJrSvcvplqws/yGXVbUEMZi/iHpZdSPWA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v5 v5.0.0 h1:5n7dPVqsWfVKw+ZiEKSd3Kzu7gwBkbEBkeXb8rgaE9Q=