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

[v13] Add an option to bootstrap database service to teleport discovery boostrap #29002

Merged
merged 3 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
131 changes: 89 additions & 42 deletions lib/configurators/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"golang.org/x/exp/slices"

"github.com/gravitational/teleport/api/types"
apiutils "github.com/gravitational/teleport/api/utils"
apiawsutils "github.com/gravitational/teleport/api/utils/aws"
awslib "github.com/gravitational/teleport/lib/cloud/aws"
"github.com/gravitational/teleport/lib/configurators"
Expand All @@ -48,10 +49,10 @@ import (
)

const (
// DefaultPolicyName default policy name.
DefaultPolicyName = "DatabaseAccess"
// DatabaseAccessPolicyName is the policy name for database access.
DatabaseAccessPolicyName = "DatabaseAccess"
// databasePolicyDescription description used on the policy created.
databasePolicyDescription = "Used by Teleport database agents for discovering AWS-hosted databases."
databasePolicyDescription = "Used by Teleport database agents for accessing AWS-hosted databases."
// discoveryServicePolicyDescription description used on the policy created.
discoveryServicePolicyDescription = "Used by Teleport the discovery service to discover AWS-hosted services."
// boundarySuffix boundary policies will have this suffix.
Expand All @@ -70,39 +71,71 @@ type databaseActions struct {
// iamAuth is a list of actions used for enabling IAM auth.
iamAuth []string
// metadata is a list of actions used for fetching database metadata
// (excluding the ones already in "discovery").
metadata []string
// managedUsers is a list of actions used for managing database users.
managedUsers []string
// boundary is a list of actions only used for boundary policies.
boundary []string
// authBoundary is a list of actions for authorization that need to added
// to boundary policies.
authBoundary []string

requireIAMEdit bool
requireSecretsManager bool
}

func (a databaseActions) buildStatementForDiscovery() *awslib.Statement {
// Note that currently extra boundary policies are not required for discovery service.
func (a databaseActions) buildStatement(opt databaseActionsBuildOption) *awslib.Statement {
var actions []string
if opt.withDiscovery {
actions = append(actions, a.discovery...)
}
if opt.withMetadata {
actions = append(actions, a.metadata...)
}
if opt.withAuth {
actions = append(actions, a.iamAuth...)
actions = append(actions, a.managedUsers...)
}
if opt.withAuthBoundary {
actions = append(actions, a.authBoundary...)
}
return &awslib.Statement{
Effect: awslib.EffectAllow,
Actions: a.discovery,
Actions: apiutils.Deduplicate(actions),
Resources: []string{"*"},
}
}

func (a databaseActions) buildStatement(boundary bool) *awslib.Statement {
var actions []string
actions = append(actions, a.discovery...)
actions = append(actions, a.iamAuth...)
actions = append(actions, a.metadata...)
actions = append(actions, a.managedUsers...)
if boundary {
actions = append(actions, a.boundary...)
}
return &awslib.Statement{
Effect: awslib.EffectAllow,
Actions: actions,
Resources: []string{"*"},
type databaseActionsBuildOption struct {
withDiscovery bool
withMetadata bool
withAuth bool
withAuthBoundary bool
}

func makeDatabaseActionsBuildOption(flags configurators.BootstrapFlags, targetCfg targetConfig, boundary bool) databaseActionsBuildOption {
switch flags.Service {
case configurators.DiscoveryService:
return databaseActionsBuildOption{
withDiscovery: true,
}

case configurators.DatabaseServiceByDiscoveryServiceConfig:
return databaseActionsBuildOption{
withDiscovery: false,
withMetadata: false, // Discovered databases should have correct metadata.
withAuth: true,
withAuthBoundary: boundary,
}

case configurators.DatabaseService:
return databaseActionsBuildOption{
withDiscovery: true,
withMetadata: true,
withAuth: true,
withAuthBoundary: boundary,
}

default:
return databaseActionsBuildOption{}
}
}

Expand Down Expand Up @@ -138,8 +171,9 @@ var (
// instances and Aurora clusters).
rdsActions = databaseActions{
discovery: []string{"rds:DescribeDBInstances", "rds:DescribeDBClusters"},
metadata: []string{"rds:DescribeDBInstances", "rds:DescribeDBClusters"},
iamAuth: []string{"rds:ModifyDBInstance", "rds:ModifyDBCluster"},
boundary: []string{"rds-db:connect"},
authBoundary: []string{"rds-db:connect"},
requireIAMEdit: true,
}
// rdsProxyActions contains IAM actions for services.AWSMatcherRDSProxy.
Expand All @@ -150,13 +184,18 @@ var (
"rds:DescribeDBProxyTargets",
"rds:ListTagsForResource",
},
boundary: []string{"rds-db:connect"},
metadata: []string{
"rds:DescribeDBProxies",
"rds:DescribeDBProxyEndpoints",
},
authBoundary: []string{"rds-db:connect"},
requireIAMEdit: true,
}
// redshiftActions contains IAM actions for services.AWSMatcherRedshift.
redshiftActions = databaseActions{
discovery: []string{"redshift:DescribeClusters"},
boundary: []string{"redshift:GetClusterCredentials"},
metadata: []string{"redshift:DescribeClusters"},
authBoundary: []string{"redshift:GetClusterCredentials"},
requireIAMEdit: true,
}
// redshiftServerlessActions contains IAM actions for services.AWSMatcherRedshiftServerless.
Expand All @@ -170,7 +209,7 @@ var (
"redshift-serverless:GetEndpointAccess",
"redshift-serverless:GetWorkgroup",
},
boundary: stsActions,
authBoundary: stsActions,
}
// elastiCacheActions contains IAM actions for services.AWSMatcherElastiCache.
elastiCacheActions = databaseActions{
Expand All @@ -180,12 +219,15 @@ var (
"elasticache:DescribeCacheClusters",
"elasticache:DescribeCacheSubnetGroups",
},
metadata: []string{
"elasticache:DescribeReplicationGroups",
},
managedUsers: []string{
"elasticache:DescribeUsers",
"elasticache:ModifyUser",
},
requireSecretsManager: true,
boundary: []string{"elasticache:Connect"},
authBoundary: []string{"elasticache:Connect"},
requireIAMEdit: true,
}
// memoryDBActions contains IAM actions for services.AWSMatcherMemoryDB.
Expand All @@ -195,6 +237,9 @@ var (
"memorydb:DescribeClusters",
"memorydb:DescribeSubnetGroups",
},
metadata: []string{
"memorydb:DescribeClusters",
},
managedUsers: []string{
"memorydb:DescribeUsers",
"memorydb:UpdateUser",
Expand All @@ -203,11 +248,11 @@ var (
}
// awsKeyspacesActions contains IAM actions for static AWS Keyspaces databases.
awsKeyspacesActions = databaseActions{
boundary: stsActions,
authBoundary: stsActions,
}
// dynamodbActions contains IAM actions for static AWS DynamoDB databases.
dynamodbActions = databaseActions{
boundary: stsActions,
authBoundary: stsActions,
}
)

Expand Down Expand Up @@ -311,6 +356,11 @@ func (a *awsConfigurator) Name() string {
return "AWS"
}

// Description returns a brief description of the configurator.
func (a *awsConfigurator) Description() string {
return "Configure AWS for " + a.config.Flags.Service.Name()
}

// Actions list of configurator actions.
func (a *awsConfigurator) Actions() []configurators.ConfiguratorAction {
return a.actions
Expand Down Expand Up @@ -492,7 +542,7 @@ func buildActions(config ConfiguratorConfig) ([]configurators.ConfiguratorAction
return nil, trace.Wrap(err)
}

if config.Flags.DiscoveryService {
if config.Flags.Service.IsDiscovery() {
return buildDiscoveryActions(config, targetCfg)
}
return buildCommonActions(config, targetCfg)
Expand Down Expand Up @@ -582,7 +632,7 @@ func buildPolicyDocument(flags configurators.BootstrapFlags, targetCfg targetCon
policyName += boundarySuffix
}

if flags.DiscoveryService {
if flags.Service.IsDiscovery() {
policyDescription = discoveryServicePolicyDescription

if isEC2AutoDiscoveryEnabled(flags, targetCfg.awsMatchers) {
Expand Down Expand Up @@ -618,13 +668,10 @@ func buildPolicyDocument(flags configurators.BootstrapFlags, targetCfg targetCon
allActions = append(allActions, dynamodbActions)
}

dbOption := makeDatabaseActionsBuildOption(flags, targetCfg, boundary)
for _, dbActions := range allActions {
if flags.DiscoveryService {
policyDoc.EnsureStatements(dbActions.buildStatementForDiscovery())
} else {
policyDoc.EnsureStatements(dbActions.buildStatement(boundary))

// Skip these for discovery service.
policyDoc.EnsureStatements(dbActions.buildStatement(dbOption))
if dbOption.withAuth {
requireSecretsManager = requireSecretsManager || dbActions.requireSecretsManager
requireIAMEdit = requireIAMEdit || dbActions.requireIAMEdit
}
Expand Down Expand Up @@ -767,7 +814,7 @@ func hasAWSKeyspacesDatabases(flags configurators.BootstrapFlags, targetCfg targ
return true
}
// There is no auto discovery for AWS Keyspaces.
if flags.DiscoveryService {
if flags.Service.IsDiscovery() {
return false
}
return findDatabaseIs(targetCfg.databases, func(database *servicecfg.Database) bool {
Expand All @@ -781,7 +828,7 @@ func hasDynamoDBDatabases(flags configurators.BootstrapFlags, targetCfg targetCo
return true
}
// There is no auto discovery for AWS DynamoDB.
if flags.DiscoveryService {
if flags.Service.IsDiscovery() {
return false
}
return findDatabaseIs(targetCfg.databases, func(database *servicecfg.Database) bool {
Expand Down Expand Up @@ -1061,7 +1108,7 @@ func getTargetConfig(flags configurators.BootstrapFlags, cfg *servicecfg.Config,
// awsMatchersFromConfig is a helper function that extracts database AWS matchers
// from the service configuration based on cli flags.
func awsMatchersFromConfig(flags configurators.BootstrapFlags, cfg *servicecfg.Config) []types.AWSMatcher {
if flags.DiscoveryService {
if flags.Service.UseDiscoveryServiceConfig() {
return cfg.Discovery.AWSMatchers
}
return cfg.Databases.AWSMatchers
Expand All @@ -1070,7 +1117,7 @@ func awsMatchersFromConfig(flags configurators.BootstrapFlags, cfg *servicecfg.C
// databasesFromConfig is a helper function that extracts databases
// from the service configuration based on cli flags.
func databasesFromConfig(flags configurators.BootstrapFlags, cfg *servicecfg.Config) []*servicecfg.Database {
if flags.DiscoveryService {
if flags.Service.UseDiscoveryServiceConfig() {
return nil
}
databases := make([]*servicecfg.Database, 0, len(cfg.Databases.Databases))
Expand All @@ -1081,7 +1128,7 @@ func databasesFromConfig(flags configurators.BootstrapFlags, cfg *servicecfg.Con
}

func resourceMatchersFromConfig(flags configurators.BootstrapFlags, cfg *servicecfg.Config) []services.ResourceMatcher {
if flags.DiscoveryService {
if flags.Service.UseDiscoveryServiceConfig() {
return nil
}
return cfg.Databases.ResourceMatchers
Expand Down