mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-24 16:17:11 +08:00
Adding the Azure sync module functions along with new cloud client functionality (#50366)
* Protobuf and configuration for Access Graph Azure Discovery * Adding the Azure sync module functions along with new cloud client functionality * Forgot to decouple role definitions fetching function from the fetcher * Moving reconciliation to the upstream azure sync PR * Moving reconciliation test to the upstream azure sync PR * Updating go.sum * Fixing rebase after protobuf gen * Nolinting until upstream PRs * Updating to use existing msgraph client * Adding protection around nil values * PR feedback * Updating principal fetching to incorporate metadata from principal subtypes * Updating opts to not leak URL parameters * Conformant package name * Using variadic options * PR feedback * Removing memberOf expansion * Expanding memberships by calling memberOf on each user * Also returning expanded principals for improved readability * Removing ptrToList * PR feedback * Rebase go.sum stuff * Go mod tidy * Linting * Linting * Collecting errors from fetching memberships and using a WithContext error group * Fixing go.mod * Update lib/msgraph/paginated.go Co-authored-by: Tiago Silva <tiago.silva@goteleport.com> * PR feedback * e ref update * e ref update * Fixing method * Fetching group members from groups rather than memberships of each principal * Linting --------- Co-authored-by: Tiago Silva <tiago.silva@goteleport.com>
This commit is contained in:
co-authored by
Tiago Silva
parent
b6e2badbe9
commit
47f4498b76
@@ -16,6 +16,7 @@ require (
|
||||
connectrpc.com/connect v1.18.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.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.2.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
|
||||
|
||||
@@ -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/v2 v2.2.0 h1:Hp+EScFOu9HeCbeW8WU2yQPJd4gGwhMgKxWe+G6jNzw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0/go.mod h1:/pz8dyNQe+Ey3yBp/XuYz7oqX8YDNWVpPB0hH3XWfbc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.0 h1:JAebRMoc3vL+Nd97GBprHYHucO4+wlW+tNbBIumqJlk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.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=
|
||||
|
||||
@@ -37,6 +37,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 // indirect
|
||||
|
||||
@@ -631,6 +631,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/v2 v2.2.0 h1:Hp+EScFOu9HeCbeW8WU2yQPJd4gGwhMgKxWe+G6jNzw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0/go.mod h1:/pz8dyNQe+Ey3yBp/XuYz7oqX8YDNWVpPB0hH3XWfbc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.0 h1:JAebRMoc3vL+Nd97GBprHYHucO4+wlW+tNbBIumqJlk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.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=
|
||||
|
||||
@@ -43,6 +43,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 // indirect
|
||||
|
||||
@@ -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/v2 v2.2.0 h1:Hp+EScFOu9HeCbeW8WU2yQPJd4gGwhMgKxWe+G6jNzw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0/go.mod h1:/pz8dyNQe+Ey3yBp/XuYz7oqX8YDNWVpPB0hH3XWfbc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.0 h1:JAebRMoc3vL+Nd97GBprHYHucO4+wlW+tNbBIumqJlk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.2.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=
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2024 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 azure
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2"
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
// RoleAssignmentsClient wraps the Azure API to provide a high level subset of functionality
|
||||
type RoleAssignmentsClient struct {
|
||||
cli *armauthorization.RoleAssignmentsClient
|
||||
}
|
||||
|
||||
// NewRoleAssignmentsClient creates a new client for a given subscription and credentials
|
||||
func NewRoleAssignmentsClient(subscription string, cred azcore.TokenCredential, options *arm.ClientOptions) (*RoleAssignmentsClient, error) {
|
||||
clientFactory, err := armauthorization.NewClientFactory(subscription, cred, options)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
roleDefCli := clientFactory.NewRoleAssignmentsClient()
|
||||
return &RoleAssignmentsClient{cli: roleDefCli}, nil
|
||||
}
|
||||
|
||||
// ListRoleAssignments returns role assignments for a given scope
|
||||
func (c *RoleAssignmentsClient) ListRoleAssignments(ctx context.Context, scope string) ([]*armauthorization.RoleAssignment, error) {
|
||||
pager := c.cli.NewListForScopePager(scope, nil)
|
||||
var roleDefs []*armauthorization.RoleAssignment
|
||||
for pager.More() {
|
||||
page, err := pager.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
roleDefs = append(roleDefs, page.Value...)
|
||||
}
|
||||
return roleDefs, nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2024 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 azure
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2"
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
// RoleDefinitionsClient wraps the Azure API to provide a high level subset of functionality
|
||||
type RoleDefinitionsClient struct {
|
||||
cli *armauthorization.RoleDefinitionsClient
|
||||
}
|
||||
|
||||
// NewRoleDefinitionsClient creates a new client for a given subscription and credentials
|
||||
func NewRoleDefinitionsClient(subscription string, cred azcore.TokenCredential, options *arm.ClientOptions) (*RoleDefinitionsClient, error) {
|
||||
clientFactory, err := armauthorization.NewClientFactory(subscription, cred, options)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
roleDefCli := clientFactory.NewRoleDefinitionsClient()
|
||||
return &RoleDefinitionsClient{cli: roleDefCli}, nil
|
||||
}
|
||||
|
||||
// ListRoleDefinitions returns role definitions for a given scope
|
||||
func (c *RoleDefinitionsClient) ListRoleDefinitions(ctx context.Context, scope string) ([]*armauthorization.RoleDefinition, error) {
|
||||
pager := c.cli.NewListPager(scope, nil)
|
||||
var roleDefs []*armauthorization.RoleDefinition
|
||||
for pager.More() {
|
||||
page, err := pager.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
roleDefs = append(roleDefs, page.Value...)
|
||||
}
|
||||
return roleDefs, nil
|
||||
}
|
||||
+27
-1
@@ -344,6 +344,10 @@ type azureClients struct {
|
||||
azurePostgresFlexServersClients azure.ClientMap[azure.PostgresFlexServersClient]
|
||||
// azureRunCommandClients contains the cached Azure Run Command clients.
|
||||
azureRunCommandClients azure.ClientMap[azure.RunCommandClient]
|
||||
// azureRoleDefinitionsClients contains the cached Azure Role Definitions clients.
|
||||
azureRoleDefinitionsClients azure.ClientMap[azure.RoleDefinitionsClient]
|
||||
// azureRoleAssignmentsClients contains the cached Azure Role Assignments clients.
|
||||
azureRoleAssignmentsClients azure.ClientMap[azure.RoleAssignmentsClient]
|
||||
}
|
||||
|
||||
// credentialsSource defines where the credentials must come from.
|
||||
@@ -717,6 +721,16 @@ func (c *cloudClients) GetAzureRunCommandClient(subscription string) (azure.RunC
|
||||
return c.azureRunCommandClients.Get(subscription, c.GetAzureCredential)
|
||||
}
|
||||
|
||||
// GetAzureRoleDefinitionsClient returns an Azure Role Definitions client
|
||||
func (c *cloudClients) GetAzureRoleDefinitionsClient(subscription string) (azure.RoleDefinitionsClient, error) {
|
||||
return c.azureRoleDefinitionsClients.Get(subscription, c.GetAzureCredential)
|
||||
}
|
||||
|
||||
// GetAzureRoleAssignmentsClient returns an Azure Role Assignments client
|
||||
func (c *cloudClients) GetAzureRoleAssignmentsClient(subscription string) (azure.RoleAssignmentsClient, error) {
|
||||
return c.azureRoleAssignmentsClients.Get(subscription, c.GetAzureCredential)
|
||||
}
|
||||
|
||||
// Close closes all initialized clients.
|
||||
func (c *cloudClients) Close() (err error) {
|
||||
c.mtx.Lock()
|
||||
@@ -1021,6 +1035,8 @@ type TestCloudClients struct {
|
||||
AzureMySQLFlex azure.MySQLFlexServersClient
|
||||
AzurePostgresFlex azure.PostgresFlexServersClient
|
||||
AzureRunCommand azure.RunCommandClient
|
||||
AzureRoleDefinitions azure.RoleDefinitionsClient
|
||||
AzureRoleAssignments azure.RoleAssignmentsClient
|
||||
}
|
||||
|
||||
// GetAWSSession returns AWS session for the specified region, optionally
|
||||
@@ -1244,11 +1260,21 @@ func (c *TestCloudClients) GetAzurePostgresFlexServersClient(subscription string
|
||||
return c.AzurePostgresFlex, nil
|
||||
}
|
||||
|
||||
// GetAzureRunCommand returns an Azure Run Command client for the given subscription.
|
||||
// GetAzureRunCommandClient returns an Azure Run Command client for the given subscription.
|
||||
func (c *TestCloudClients) GetAzureRunCommandClient(subscription string) (azure.RunCommandClient, error) {
|
||||
return c.AzureRunCommand, nil
|
||||
}
|
||||
|
||||
// GetAzureRoleDefinitionsClient returns an Azure Role Definitions client for the given subscription.
|
||||
func (c *TestCloudClients) GetAzureRoleDefinitionsClient(subscription string) (azure.RoleDefinitionsClient, error) {
|
||||
return c.AzureRoleDefinitions, nil
|
||||
}
|
||||
|
||||
// GetAzureRoleAssignmentsClient returns an Azure Role Assignments client for the given subscription.
|
||||
func (c *TestCloudClients) GetAzureRoleAssignmentsClient(subscription string) (azure.RoleAssignmentsClient, error) {
|
||||
return c.AzureRoleAssignments, nil
|
||||
}
|
||||
|
||||
// Close closes all initialized clients.
|
||||
func (c *TestCloudClients) Close() error {
|
||||
return nil
|
||||
|
||||
@@ -101,6 +101,14 @@ func (c *Client) IterateUsers(ctx context.Context, f func(*User) bool) error {
|
||||
return iterateSimple(c, ctx, "users", f)
|
||||
}
|
||||
|
||||
// IterateServicePrincipals lists all service principals in the Entra ID directory using pagination.
|
||||
// `f` will be called for each object in the result set.
|
||||
// if `f` returns `false`, the iteration is stopped (equivalent to `break` in a normal loop).
|
||||
// Ref: [https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list].
|
||||
func (c *Client) IterateServicePrincipals(ctx context.Context, f func(principal *ServicePrincipal) bool) error {
|
||||
return iterateSimple(c, ctx, "servicePrincipals", f)
|
||||
}
|
||||
|
||||
// IterateGroupMembers lists all members for the given Entra ID group using pagination.
|
||||
// `f` will be called for each object in the result set.
|
||||
// if `f` returns `false`, the iteration is stopped (equivalent to `break` in a normal loop).
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Teleport
|
||||
* 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 azuresync
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha"
|
||||
"github.com/gravitational/teleport/lib/msgraph"
|
||||
)
|
||||
|
||||
const parallelism = 10 //nolint:unused // invoked in a dependent PR
|
||||
|
||||
// expandMemberships adds membership data to AzurePrincipal objects by querying the Graph API for group memberships
|
||||
func expandMemberships(ctx context.Context, cli *msgraph.Client, principals []*accessgraphv1alpha.AzurePrincipal) ([]*accessgraphv1alpha.AzurePrincipal, error) { //nolint:unused // invoked in a dependent PR
|
||||
// Map principals by ID
|
||||
var principalsMap = make(map[string]*accessgraphv1alpha.AzurePrincipal)
|
||||
for _, principal := range principals {
|
||||
principalsMap[principal.Id] = principal
|
||||
}
|
||||
// Iterate through the Azure groups and add the group ID as a membership for its corresponding principal
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
eg.SetLimit(parallelism)
|
||||
errCh := make(chan error, len(principals))
|
||||
for _, principal := range principals {
|
||||
if principal.ObjectType != "group" {
|
||||
continue
|
||||
}
|
||||
group := principal
|
||||
eg.Go(func() error {
|
||||
err := cli.IterateGroupMembers(ctx, group.Id, func(member msgraph.GroupMember) bool {
|
||||
if memberPrincipal, ok := principalsMap[*member.GetID()]; ok {
|
||||
memberPrincipal.MemberOf = append(memberPrincipal.MemberOf, group.Id)
|
||||
}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
_ = eg.Wait()
|
||||
close(errCh)
|
||||
return principals, trace.NewAggregateFromChannel(errCh, ctx)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2024 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 azuresync
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha"
|
||||
"github.com/gravitational/teleport/lib/msgraph"
|
||||
)
|
||||
|
||||
type dirObjMetadata struct { //nolint:unused // invoked in a dependent PR
|
||||
objectType string
|
||||
}
|
||||
|
||||
type queryResult struct { //nolint:unused // invoked in a dependent PR
|
||||
metadata dirObjMetadata
|
||||
dirObj msgraph.DirectoryObject
|
||||
}
|
||||
|
||||
// fetchPrincipals fetches the Azure principals (users, groups, and service principals) using the Graph API
|
||||
func fetchPrincipals(ctx context.Context, subscriptionID string, cli *msgraph.Client) ([]*accessgraphv1alpha.AzurePrincipal, error) { //nolint: unused // invoked in a dependent PR
|
||||
// Fetch the users, groups, and service principals as directory objects
|
||||
var queryResults []queryResult
|
||||
err := cli.IterateUsers(ctx, func(user *msgraph.User) bool {
|
||||
res := queryResult{metadata: dirObjMetadata{objectType: "user"}, dirObj: user.DirectoryObject}
|
||||
queryResults = append(queryResults, res)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
err = cli.IterateGroups(ctx, func(group *msgraph.Group) bool {
|
||||
res := queryResult{metadata: dirObjMetadata{objectType: "group"}, dirObj: group.DirectoryObject}
|
||||
queryResults = append(queryResults, res)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
err = cli.IterateServicePrincipals(ctx, func(servicePrincipal *msgraph.ServicePrincipal) bool {
|
||||
res := queryResult{metadata: dirObjMetadata{objectType: "servicePrincipal"}, dirObj: servicePrincipal.DirectoryObject}
|
||||
queryResults = append(queryResults, res)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Return the users, groups, and service principals as protobuf messages
|
||||
var fetchErrs []error
|
||||
var pbPrincipals []*accessgraphv1alpha.AzurePrincipal
|
||||
for _, res := range queryResults {
|
||||
if res.dirObj.ID == nil || res.dirObj.DisplayName == nil {
|
||||
fetchErrs = append(fetchErrs,
|
||||
trace.BadParameter("nil values on msgraph directory object: %v", res.dirObj))
|
||||
continue
|
||||
}
|
||||
pbPrincipals = append(pbPrincipals, &accessgraphv1alpha.AzurePrincipal{
|
||||
Id: *res.dirObj.ID,
|
||||
SubscriptionId: subscriptionID,
|
||||
LastSyncTime: timestamppb.Now(),
|
||||
DisplayName: *res.dirObj.DisplayName,
|
||||
ObjectType: res.metadata.objectType,
|
||||
})
|
||||
}
|
||||
return pbPrincipals, trace.NewAggregate(fetchErrs...)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2024 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 azuresync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2"
|
||||
"github.com/gravitational/trace"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha"
|
||||
)
|
||||
|
||||
// RoleAssignmentsClient specifies the methods used to fetch role assignments from Azure
|
||||
type RoleAssignmentsClient interface {
|
||||
ListRoleAssignments(ctx context.Context, scope string) ([]*armauthorization.RoleAssignment, error)
|
||||
}
|
||||
|
||||
// fetchRoleAssignments fetches Azure role assignments using the Azure role assignments API
|
||||
func fetchRoleAssignments(ctx context.Context, subscriptionID string, cli RoleAssignmentsClient) ([]*accessgraphv1alpha.AzureRoleAssignment, error) { //nolint:unused // invoked in a dependent PR
|
||||
// List the role definitions
|
||||
roleAssigns, err := cli.ListRoleAssignments(ctx, fmt.Sprintf("/subscriptions/%s", subscriptionID))
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Convert to protobuf format
|
||||
pbRoleAssigns := make([]*accessgraphv1alpha.AzureRoleAssignment, 0, len(roleAssigns))
|
||||
var fetchErrs []error
|
||||
for _, roleAssign := range roleAssigns {
|
||||
if roleAssign.ID == nil ||
|
||||
roleAssign.Properties == nil ||
|
||||
roleAssign.Properties.PrincipalID == nil ||
|
||||
roleAssign.Properties.Scope == nil {
|
||||
fetchErrs = append(fetchErrs,
|
||||
trace.BadParameter("nil values on AzureRoleAssignment object: %v", roleAssign))
|
||||
continue
|
||||
}
|
||||
pbRoleAssign := &accessgraphv1alpha.AzureRoleAssignment{
|
||||
Id: *roleAssign.ID,
|
||||
SubscriptionId: subscriptionID,
|
||||
LastSyncTime: timestamppb.Now(),
|
||||
PrincipalId: *roleAssign.Properties.PrincipalID,
|
||||
RoleDefinitionId: *roleAssign.Properties.RoleDefinitionID,
|
||||
Scope: *roleAssign.Properties.Scope,
|
||||
}
|
||||
pbRoleAssigns = append(pbRoleAssigns, pbRoleAssign)
|
||||
}
|
||||
return pbRoleAssigns, trace.NewAggregate(fetchErrs...)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2024 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 azuresync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2"
|
||||
"github.com/gravitational/trace"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha"
|
||||
"github.com/gravitational/teleport/lib/utils/slices"
|
||||
)
|
||||
|
||||
// RoleDefinitionsClient specifies the methods used to fetch roles from Azure
|
||||
type RoleDefinitionsClient interface {
|
||||
ListRoleDefinitions(ctx context.Context, scope string) ([]*armauthorization.RoleDefinition, error)
|
||||
}
|
||||
|
||||
func fetchRoleDefinitions(ctx context.Context, subscriptionID string, cli RoleDefinitionsClient) ([]*accessgraphv1alpha.AzureRoleDefinition, error) { //nolint:unused // used in a dependent PR
|
||||
// List the role definitions
|
||||
roleDefs, err := cli.ListRoleDefinitions(ctx, fmt.Sprintf("/subscriptions/%s", subscriptionID))
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Convert to protobuf format
|
||||
pbRoleDefs := make([]*accessgraphv1alpha.AzureRoleDefinition, 0, len(roleDefs))
|
||||
var fetchErrs []error
|
||||
for _, roleDef := range roleDefs {
|
||||
if roleDef.ID == nil ||
|
||||
roleDef.Properties == nil ||
|
||||
roleDef.Properties.Permissions == nil ||
|
||||
roleDef.Properties.RoleName == nil {
|
||||
fetchErrs = append(fetchErrs, trace.BadParameter("nil values on AzureRoleDefinition object: %v", roleDef))
|
||||
continue
|
||||
}
|
||||
pbPerms := make([]*accessgraphv1alpha.AzureRBACPermission, 0, len(roleDef.Properties.Permissions))
|
||||
for _, perm := range roleDef.Properties.Permissions {
|
||||
if perm.Actions == nil && perm.NotActions == nil {
|
||||
fetchErrs = append(fetchErrs, trace.BadParameter("nil values on Permission object: %v", perm))
|
||||
continue
|
||||
}
|
||||
pbPerm := accessgraphv1alpha.AzureRBACPermission{
|
||||
Actions: slices.FromPointers(perm.Actions),
|
||||
NotActions: slices.FromPointers(perm.NotActions),
|
||||
}
|
||||
pbPerms = append(pbPerms, &pbPerm)
|
||||
}
|
||||
pbRoleDef := &accessgraphv1alpha.AzureRoleDefinition{
|
||||
Id: *roleDef.ID,
|
||||
Name: *roleDef.Properties.RoleName,
|
||||
SubscriptionId: subscriptionID,
|
||||
LastSyncTime: timestamppb.Now(),
|
||||
Permissions: pbPerms,
|
||||
}
|
||||
pbRoleDefs = append(pbRoleDefs, pbRoleDef)
|
||||
}
|
||||
return pbRoleDefs, trace.NewAggregate(fetchErrs...)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Teleport
|
||||
* Copyright (C) 2024 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 azuresync
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6"
|
||||
"github.com/gravitational/trace"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha"
|
||||
)
|
||||
|
||||
const allResourceGroups = "*" //nolint:unused // invoked in a dependent PR
|
||||
|
||||
// VirtualMachinesClient specifies the methods used to fetch virtual machines from Azure
|
||||
type VirtualMachinesClient interface {
|
||||
ListVirtualMachines(ctx context.Context, resourceGroup string) ([]*armcompute.VirtualMachine, error)
|
||||
}
|
||||
|
||||
func fetchVirtualMachines(ctx context.Context, subscriptionID string, cli VirtualMachinesClient) ([]*accessgraphv1alpha.AzureVirtualMachine, error) { //nolint:unused // invoked in a dependent PR
|
||||
vms, err := cli.ListVirtualMachines(ctx, allResourceGroups)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Return the VMs as protobuf messages
|
||||
pbVms := make([]*accessgraphv1alpha.AzureVirtualMachine, 0, len(vms))
|
||||
var fetchErrs []error
|
||||
for _, vm := range vms {
|
||||
if vm.ID == nil || vm.Name == nil {
|
||||
fetchErrs = append(fetchErrs, trace.BadParameter("nil values on AzureVirtualMachine object: %v", vm))
|
||||
continue
|
||||
}
|
||||
pbVm := accessgraphv1alpha.AzureVirtualMachine{
|
||||
Id: *vm.ID,
|
||||
SubscriptionId: subscriptionID,
|
||||
LastSyncTime: timestamppb.Now(),
|
||||
Name: *vm.Name,
|
||||
}
|
||||
pbVms = append(pbVms, &pbVm)
|
||||
}
|
||||
return pbVms, trace.NewAggregate(fetchErrs...)
|
||||
}
|
||||
Reference in New Issue
Block a user