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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions integrations/terraform/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvUL
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ=
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing godoc


// 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
// RoleName is the name of the Azure Role to create and assign to the managed identity
RoleName 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
170 changes: 170 additions & 0 deletions lib/integrations/azureoidc/accessgraph_sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Copyright (C) 2024 Gravitational, Inc.
* 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 azureoidc

import (
"context"
"fmt"
"os"
"slices"
"strings"

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization"
"github.com/google/uuid"
"github.com/gravitational/trace"

"github.com/gravitational/teleport/lib/cloud/provisioning"
"github.com/gravitational/teleport/lib/config"
"github.com/gravitational/teleport/lib/msgraph"
tslices "github.com/gravitational/teleport/lib/utils/slices"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we name this libslices? It's the name being used in other places when importing this package.
Also, I think it's somewhat of a convention to name libX for any X package under teleport/lib/ directory

)

// graphAppId is the pre-defined application ID of the Graph API
// Ref: [https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/governance/verify-first-party-apps-sign-in#application-ids-of-commonly-used-microsoft-applications].
const graphAppId = "00000003-0000-0000-c000-000000000000"

var requiredGraphRoleNames = []string{
"User.ReadBasic.All",
"Group.Read.All",
"Directory.Read.All",
"User.Read.All",
"Policy.Read.All",
}

func newManagedIdAction(cred *azidentity.DefaultAzureCredential, subId string, managedId string, roleName string) (*provisioning.Action, error) {
runnerFn := func(ctx context.Context) error {
// Create the role
roleDefCli, err := armauthorization.NewRoleDefinitionsClient(cred, nil)
if err != nil {
return trace.Wrap(fmt.Errorf("failed to create role definitions client: %w", err))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return trace.Wrap(fmt.Errorf("failed to create role definitions client: %w", err))
return trace.BadParameter("failed to create role definitions client: %v", err)

Same for all the others

}
roleDefId := uuid.New().String()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care that uuid.New() could panic? Should this use uuid.NewRandom?

customRole := "CustomRole"
scope := fmt.Sprintf("/subscriptions/%s", subId)
Comment on lines +59 to +60
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we instantiate these variables before the runnerFn? This way they are only built once.

Also, I think concatenating strings is faster then calling fmt.Sprintf, but up to you 👍

Suggested change
customRole := "CustomRole"
scope := fmt.Sprintf("/subscriptions/%s", subId)
customRole := "CustomRole"
scope := "/subscriptions/" + subId

roleDefinition := armauthorization.RoleDefinition{
Name: &roleDefId,
Properties: &armauthorization.RoleDefinitionProperties{
RoleName: &roleName,
RoleType: &customRole,
Permissions: []*armauthorization.Permission{
{
Actions: tslices.ToPointers([]string{
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/virtualMachineScaleSets/virtualMachines/read",
"Microsoft.Authorization/roleDefinitions/read",
"Microsoft.Authorization/roleAssignments/read",
}),
},
},
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: %w", err))
}

// Assign the new role to the managed identity
roleAssignCli, err := armauthorization.NewRoleAssignmentsClient(subId, cred, nil)
if err != nil {
return fmt.Errorf("failed to create role assignments client: %w", err)
}
assignName := uuid.New().String()
if err != nil {
return trace.Wrap(fmt.Errorf("failed to create role assignments client: %w", err))
}
Comment on lines +90 to +92
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if err != nil {
return trace.Wrap(fmt.Errorf("failed to create role assignments client: %w", err))
}

roleAssignParams := armauthorization.RoleAssignmentCreateParameters{
Properties: &armauthorization.RoleAssignmentProperties{
PrincipalID: &managedId,
RoleDefinitionID: roleRes.ID,
},
}
_, err = roleAssignCli.Create(ctx, scope, assignName, roleAssignParams, nil)
if err != nil {
return fmt.Errorf(
"failed to assign role %s to principal %s: %w", roleName, managedId, err)
}
Comment on lines +99 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer shorter variable scopes when possible.

Suggested change
_, err = roleAssignCli.Create(ctx, scope, assignName, roleAssignParams, nil)
if err != nil {
return fmt.Errorf(
"failed to assign role %s to principal %s: %w", roleName, managedId, err)
}
if err := roleAssignCli.Create(ctx, scope, assignName, roleAssignParams, nil); err != nil {
return fmt.Errorf(
"failed to assign role %s to principal %s: %w", roleName, managedId, err)
}


// Assign the Graph API permissions to the managed identity
graphCli, err := msgraph.NewClient(msgraph.Config{
TokenProvider: cred,
})
if err != nil {
return trace.Wrap(fmt.Errorf("failed to create msgraph client: %w", err))
}
graphPrincipal, err := graphCli.GetServicePrincipalByAppId(ctx, graphAppId)
if err != nil {
return trace.Wrap(fmt.Errorf("failed to get the graph API service principal: %w", err))
}
var graphRoleIds []string
for _, appRole := range graphPrincipal.AppRoles {
if slices.Contains(requiredGraphRoleNames, *appRole.Value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: make requiredGraphRoleNames a map[string]struct{} and ditch slices.Contains

graphRoleIds = append(graphRoleIds, *appRole.ID)
}
}
for _, graphRoleId := range graphRoleIds {
_, err := graphCli.GrantAppRoleToServicePrincipal(ctx, managedId, &msgraph.AppRoleAssignment{
AppRoleID: &graphRoleId,
PrincipalID: &managedId,
ResourceID: graphPrincipal.ID,
})
if err != nil {
return trace.Wrap(fmt.Errorf("failed to assign graph API role to %s: %w", managedId, err))
}
}
Comment on lines +119 to +131
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the slice and the second loop necessary?

Suggested change
graphRoleIds = append(graphRoleIds, *appRole.ID)
}
}
for _, graphRoleId := range graphRoleIds {
_, err := graphCli.GrantAppRoleToServicePrincipal(ctx, managedId, &msgraph.AppRoleAssignment{
AppRoleID: &graphRoleId,
PrincipalID: &managedId,
ResourceID: graphPrincipal.ID,
})
if err != nil {
return trace.Wrap(fmt.Errorf("failed to assign graph API role to %s: %w", managedId, err))
}
}
_, err := graphCli.GrantAppRoleToServicePrincipal(ctx, managedId, &msgraph.AppRoleAssignment{
AppRoleID: appRole.ID,
PrincipalID: &managedId,
ResourceID: graphPrincipal.ID,
})
if err != nil {
return trace.Wrap(fmt.Errorf("failed to assign graph API role to %s: %w", managedId, err))
}
}

return nil
}
cfg := provisioning.ActionConfig{
Name: "NewSyncManagedId",
Summary: "Creates a new Azure role and attaches it to a managed identity for the Discovery service",
Details: strings.Join([]string{
"The Discovery service needs to run as a credentialed Azure managed identity. This managed identity ",
"can be system assigned (i.e. tied to the lifecycle of a virtual machine running the Discovery service), ",
"or user-assigned (i.e. a persistent identity). The managed identity requires two types of permissions: ",
"1) Azure resource permissions in order to fetch virtual machines, role definitions, etc, and 2) Graph ",
"API permissions to fetch users, groups, and service principals. The command assigns both Azure resource ",
"permissions as well as Graph API permissions to the specified managed identity.",
}, ""),
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, params.RoleName)
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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the output be provided in params?

}
return trace.Wrap(provisioning.Run(ctx, opCfg))
}
9 changes: 9 additions & 0 deletions lib/msgraph/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,15 @@ func (c *Client) GetServicePrincipalsByDisplayName(ctx context.Context, displayN
return out.Value, nil
}

func (c *Client) GetServicePrincipal(ctx context.Context, principalId string) (*ServicePrincipal, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing godoc

uri := c.endpointURI(fmt.Sprintf("servicePrincipals/%s", principalId))
out, err := roundtrip[*ServicePrincipal](ctx, c, http.MethodGet, uri.String(), nil)
if err != nil {
return nil, trace.Wrap(err)
}
return out, nil
}

// GrantAppRoleToServicePrincipal grants the given app role to the specified Service Principal.
// Ref: [https://learn.microsoft.com/en-us/graph/api/serviceprincipal-post-approleassignedto]
func (c *Client) GrantAppRoleToServicePrincipal(ctx context.Context, spID string, assignment *AppRoleAssignment) (*AppRoleAssignment, error) {
Expand Down
12 changes: 9 additions & 3 deletions lib/msgraph/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ type WebApplication struct {

type ServicePrincipal struct {
DirectoryObject
AppRoleAssignmentRequired *bool `json:"appRoleAssignmentRequired,omitempty"`
PreferredSingleSignOnMode *string `json:"preferredSingleSignOnMode,omitempty"`
PreferredTokenSigningKeyThumbprint *string `json:"preferredTokenSigningKeyThumbprint,omitempty"`
AppRoleAssignmentRequired *bool `json:"appRoleAssignmentRequired,omitempty"`
PreferredSingleSignOnMode *string `json:"preferredSingleSignOnMode,omitempty"`
PreferredTokenSigningKeyThumbprint *string `json:"preferredTokenSigningKeyThumbprint,omitempty"`
AppRoles []*AppRole `json:"appRoles,omitempty"`
}

type ApplicationServicePrincipal struct {
Expand All @@ -144,6 +145,11 @@ type SelfSignedCertificate struct {
Thumbprint *string `json:"thumbprint,omitempty"`
}

type AppRole struct {
ID *string `json:"id,omitempty"`
Value *string `json:"value,omitempty"`
}

type AppRoleAssignment struct {
ID *string `json:"id,omitempty"`
AppRoleID *string `json:"appRoleId,omitempty"`
Expand Down
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.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💅
Can we please mention azure in the command description?
Same for the aws-iam command

integrationConfAccessGraphAzureSyncCmd.Flag("managed-identity", "The ID of the managed identity to run the Discovery service.").Required().StringVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.ManagedIdentity)
integrationConfAccessGraphAzureSyncCmd.Flag("role-name", "The name of the Azure Role to create and assign to the managed identity").Required().StringVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.RoleName)
integrationConfAccessGraphAzureSyncCmd.Flag("subscription-id", "The subscription ID in which to discovery resources.").StringVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.SubscriptionID)
integrationConfAccessGraphAzureSyncCmd.Flag("confirm", "Apply changes without confirmation prompt.").BoolVar(&ccf.IntegrationConfAccessGraphAzureSyncArguments.AutoConfirm)

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