Skip to content

Commit

Permalink
Godoc
Browse files Browse the repository at this point in the history
  • Loading branch information
mvbrock committed Dec 5, 2024
1 parent d45d26c commit a92ad6e
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 11 deletions.
3 changes: 3 additions & 0 deletions lib/cloud/azure/roleassignments.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ import (
"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 {
Expand All @@ -40,6 +42,7 @@ func NewRoleAssignmentsClient(subscription string, cred azcore.TokenCredential,
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)
roleDefs := make([]*armauthorization.RoleAssignment, 0, 128)
Expand Down
3 changes: 3 additions & 0 deletions lib/cloud/azure/roledefinitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ import (
"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 {
Expand All @@ -40,6 +42,7 @@ func NewRoleDefinitionsClient(subscription string, cred azcore.TokenCredential,
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)
roleDefs := make([]*armauthorization.RoleDefinition, 0, 128)
Expand Down
9 changes: 8 additions & 1 deletion lib/srv/discovery/access_graph_azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import (
azure_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/azure-sync"
)

// reconcileAccessGraphAzure fetches Azure resources, creates a set of resources to delete and upsert based on
// the previous fetch, and then sends the delete and upsert results to the Access Graph stream
func (s *Server) reconcileAccessGraphAzure(
ctx context.Context,
currentTAGResources *azure_sync.Resources,
Expand Down Expand Up @@ -114,6 +116,7 @@ func (s *Server) reconcileAccessGraphAzure(
return nil
}

// azurePushUpsertInBatches upserts resources to the Access Graph in batches
func azurePushUpsertInBatches(
client accessgraphv1alpha.AccessGraphService_AzureEventsStreamClient,
upsert *accessgraphv1alpha.AzureResourceList,
Expand All @@ -139,6 +142,7 @@ func azurePushUpsertInBatches(
return nil
}

// azurePushDeleteInBatches deletes resources from the Access Graph in batches
func azurePushDeleteInBatches(
client accessgraphv1alpha.AccessGraphService_AzureEventsStreamClient,
toDel *accessgraphv1alpha.AzureResourceList,
Expand All @@ -164,6 +168,7 @@ func azurePushDeleteInBatches(
return nil
}

// azurePush upserts and deletes Azure resources to/from the Access Graph
func azurePush(
client accessgraphv1alpha.AccessGraphService_AzureEventsStreamClient,
upsert *accessgraphv1alpha.AzureResourceList,
Expand Down Expand Up @@ -365,7 +370,9 @@ func (s *Server) initTAGAzureWatchers(ctx context.Context, cfg *Config) error {
return nil
}

func (s *Server) accessGraphAzureFetchersFromMatchers(matchers Matchers, discoveryConfigName string) ([]*azure_sync.Fetcher, error) {
// accessGraphAzureFetchersFromMatchers converts matcher configuration to fetchers for Azure resource synchronization
func (s *Server) accessGraphAzureFetchersFromMatchers(
matchers Matchers, discoveryConfigName string) ([]*azure_sync.Fetcher, error) {
var fetchers []*azure_sync.Fetcher
var errs []error
if matchers.AccessGraph == nil {
Expand Down
27 changes: 17 additions & 10 deletions lib/srv/discovery/fetchers/azure-sync/azure-sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (

const FetcherConcurrency = 5

// Config defines parameters required for fetching resources from Azure
type Config struct {
CloudClients cloud.Clients
SubscriptionID string
Expand All @@ -51,25 +52,30 @@ type Config struct {
DiscoveryConfigName string
}

// Resources represents the set of resources fetched from Azure
type Resources struct {
Principals []*accessgraphv1alpha.AzurePrincipal
RoleDefinitions []*accessgraphv1alpha.AzureRoleDefinition
RoleAssignments []*accessgraphv1alpha.AzureRoleAssignment
VirtualMachines []*accessgraphv1alpha.AzureVirtualMachine
}

// RoleDefinitionsClient specifies the methods used to fetch roles from Azure
type RoleDefinitionsClient interface {
ListRoleDefinitions(ctx context.Context, scope string) ([]*armauthorization.RoleDefinition, error)
}

// RoleAssignmentsClient specifies the methods used to fetch role assignments from Azure
type RoleAssignmentsClient interface {
ListRoleAssignments(ctx context.Context, scope string) ([]*armauthorization.RoleAssignment, error)
}

// VirtualMachinesClient specifies the methods used to fetch virtual machines from Azure
type VirtualMachinesClient interface {
ListVirtualMachines(ctx context.Context, resourceGroup string) ([]*armcompute.VirtualMachine, error)
}

// Fetcher provides the functionality for fetching resources from Azure
type Fetcher struct {
Config
lastError error
Expand All @@ -81,6 +87,7 @@ type Fetcher struct {
roleAssignClient RoleAssignmentsClient
}

// NewFetcher returns a new fetcher based on configuration parameters
func NewFetcher(cfg Config, ctx context.Context) (*Fetcher, error) {
// Establish the credential from the managed identity
cred, err := azidentity.NewDefaultAzureCredential(nil)
Expand Down Expand Up @@ -121,8 +128,7 @@ type Features struct {
AKSClusters bool
}

// BuildFeatures builds the feature flags based on supported types returned by Access Graph
// Azure endpoints.
// BuildFeatures builds the feature flags based on supported types returned by Access Graph Azure endpoints.
func BuildFeatures(values ...string) Features {
features := Features{}
for _, value := range values {
Expand All @@ -141,6 +147,7 @@ func BuildFeatures(values ...string) Features {
return features
}

// Poll fetches and deduplicates Azure resources specified by the Access Graph
func (a *Fetcher) Poll(ctx context.Context, feats Features) (*Resources, error) {
res, err := a.fetch(ctx, feats)
if res == nil {
Expand All @@ -153,6 +160,7 @@ func (a *Fetcher) Poll(ctx context.Context, feats Features) (*Resources, error)
return res, trace.Wrap(err)
}

// fetch returns the resources specified by the Access Graph
func (a *Fetcher) fetch(ctx context.Context, feats Features) (*Resources, error) {
// Accumulate Azure resources
eg, ctx := errgroup.WithContext(ctx)
Expand Down Expand Up @@ -229,23 +237,22 @@ func (a *Fetcher) fetch(ctx context.Context, feats Features) (*Resources, error)
return result, nil
}

// Status returns the number of resources last fetched and/or the last fetching/reconciling error
func (a *Fetcher) Status() (uint64, error) {
return a.lastDiscoveredResources, a.lastError
}

// DiscoveryConfigName returns the name of the configured discovery
func (a *Fetcher) DiscoveryConfigName() string {
return a.Config.DiscoveryConfigName
}

// IsFromDiscoveryConfig returns whether the discovery is from configuration or dynamic
func (a *Fetcher) IsFromDiscoveryConfig() bool {
return a.Config.DiscoveryConfigName != ""
}

// GetSubscriptionID returns the ID of the Azure subscription
func (a *Fetcher) GetSubscriptionID() string {
return a.Config.SubscriptionID
}

func ptrsToList(ptrs []*string) []string {
strList := make([]string, len(ptrs))
for _, ptr := range ptrs {
strList = append(strList, *ptr)
}
return strList
}
10 changes: 10 additions & 0 deletions lib/srv/discovery/fetchers/azure-sync/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/gravitational/teleport/lib/srv/discovery/common"
)

// MergeResources merges Azure resources fetched from multiple configured Azure fetchers
func MergeResources(results ...*Resources) *Resources {
if len(results) == 0 {
return &Resources{}
Expand All @@ -38,18 +39,25 @@ func MergeResources(results ...*Resources) *Resources {
for _, r := range results {
result.Principals = append(result.Principals, r.Principals...)
result.VirtualMachines = append(result.VirtualMachines, r.VirtualMachines...)
result.RoleDefinitions = append(result.RoleDefinitions, r.RoleDefinitions...)
result.RoleAssignments = append(result.RoleAssignments, r.RoleAssignments...)
}
result.Principals = common.DeduplicateSlice(result.Principals, azurePrincipalsKey)
result.VirtualMachines = common.DeduplicateSlice(result.VirtualMachines, azureVmKey)
result.RoleDefinitions = common.DeduplicateSlice(result.RoleDefinitions, azureRoleDefKey)
result.RoleAssignments = common.DeduplicateSlice(result.RoleAssignments, azureRoleAssignKey)
return result
}

// newResourceList creates a new resource list message
func newResourceList() *accessgraphv1alpha.AzureResourceList {
return &accessgraphv1alpha.AzureResourceList{
Resources: make([]*accessgraphv1alpha.AzureResource, 0),
}
}

// ReconcileResults compares previously and currently fetched results and determines which resources to upsert and
// which to delete.
func ReconcileResults(old *Resources, new *Resources) (upsert, delete *accessgraphv1alpha.AzureResourceList) {
upsert, delete = newResourceList(), newResourceList()
reconciledResources := []*reconcilePair{
Expand All @@ -65,10 +73,12 @@ func ReconcileResults(old *Resources, new *Resources) (upsert, delete *accessgra
return upsert, delete
}

// reconcilePair contains the Azure resources to upsert and delete
type reconcilePair struct {
upsert, delete *accessgraphv1alpha.AzureResourceList
}

// reconcile compares old and new items to build a list of resources to upsert and delete in the Access Graph
func reconcile[T proto.Message](
oldItems []T,
newItems []T,
Expand Down
8 changes: 8 additions & 0 deletions lib/srv/discovery/fetchers/azure-sync/roledefinitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,11 @@ func (a *Fetcher) fetchRoleDefinitions(ctx context.Context) ([]*accessgraphv1alp
}
return pbRoleDefs, nil
}

func ptrsToList(ptrs []*string) []string {
strList := make([]string, len(ptrs))
for _, ptr := range ptrs {
strList = append(strList, *ptr)
}
return strList
}

0 comments on commit a92ad6e

Please sign in to comment.