Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure integration commands #47541

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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 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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
15 changes: 15 additions & 0 deletions lib/config/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
107 changes: 107 additions & 0 deletions lib/integrations/azureoidc/accessgraph_sync.go
Original file line number Diff line number Diff line change
@@ -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))
}
6 changes: 6 additions & 0 deletions tool/teleport/common/integration_configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 13 additions & 5 deletions tool/teleport/common/teleport.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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():
Expand Down
Loading