diff --git a/lib/config/configuration.go b/lib/config/configuration.go index 0e47e6807cfd6..d614eeb476f81 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -350,22 +350,6 @@ type IntegrationConfAWSOIDCIdP struct { // ProxyPublicURL is the IdP Issuer URL (Teleport Proxy Public Address). // Eg, https://.teleport.sh ProxyPublicURL string - - // S3BucketURI is the S3 URI which contains the bucket name and prefix for the issuer. - // Format: s3:/// - // Eg, s3://my-bucket/idp-teleport - // This is used in two places: - // - create openid configuration and jwks objects - // - set up the issuer - // The bucket must be public and will be created if it doesn't exist. - // - // If empty, the ProxyPublicAddress is used as issuer and no s3 objects are created. - S3BucketURI string - - // S3JWKSContentsB64 must contain the public keys for the Issuer. - // The contents must be Base64 encoded. - // Eg. base64(`{"keys":[{"kty":"RSA","alg":"RS256","n":"","e":"","use":"sig","kid":""}]}`) - S3JWKSContentsB64 string } // IntegrationConfListDatabasesIAM contains the arguments of diff --git a/lib/integrations/awsoidc/idp_iam_config.go b/lib/integrations/awsoidc/idp_iam_config.go index d8c6fe716903e..c1b2036a9639f 100644 --- a/lib/integrations/awsoidc/idp_iam_config.go +++ b/lib/integrations/awsoidc/idp_iam_config.go @@ -19,22 +19,14 @@ package awsoidc import ( - "bytes" "context" - "encoding/base64" - "encoding/json" - "fmt" "log/slog" "net/http" "net/url" - "path" - "strings" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/iam" - "github.com/aws/aws-sdk-go-v2/service/s3" - s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/gravitational/trace" @@ -42,8 +34,6 @@ import ( awslib "github.com/gravitational/teleport/lib/cloud/aws" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/integrations/awsoidc/tags" - awsutil "github.com/gravitational/teleport/lib/utils/aws" - "github.com/gravitational/teleport/lib/utils/oidc" ) const ( @@ -67,33 +57,13 @@ type IdPIAMConfigureRequest struct { // ProxyPublicAddress is the URL to use as provider URL. // This must be a valid URL (ie, url.Parse'able) // Eg, https://.teleport.sh, https://proxy.example.org:443, https://teleport.ec2.aws:3080 - // Only one of ProxyPublicAddress or S3BucketLocation can be used. ProxyPublicAddress string - // S3BucketLocation is the S3 URI which contains the bucket name and prefix for the issuer. - // Format: s3:/// - // Eg, s3://my-bucket/idp-teleport - // This is used in two places: - // - create openid configuration and jwks objects - // - set up the issuer - // The bucket must be public and will be created if it doesn't exist. - // - // If empty, the ProxyPublicAddress is used as issuer and no s3 objects are created. - S3BucketLocation string - - // S3JWKSContentsB64 must contain the public keys for the Issuer. - // The contents must be Base64 encoded. - // Eg. base64(`{"keys":[{"kty":"RSA","alg":"RS256","n":"","e":"","use":"sig","kid":""}]}`) - S3JWKSContentsB64 string - s3Bucket string - s3BucketPrefix string - jwksFileContents []byte - // issuer is the above value but only contains the host. - // Eg, .teleport.sh, proxy.example.org, my-bucket.s3.amazonaws.com/my-prefix + // Eg, .teleport.sh, proxy.example.org issuer string // issuerURL is the full url for the issuer - // Eg, https://.teleport.sh, https://proxy.example.org, https://my-bucket.s3.amazonaws.com/my-prefix + // Eg, https://.teleport.sh, https://proxy.example.org issuerURL string // IntegrationRole is the Integration's AWS Role used to set up Teleport as an OIDC IdP. @@ -116,41 +86,19 @@ func (r *IdPIAMConfigureRequest) CheckAndSetDefaults() error { return trace.BadParameter("integration role is required") } - if (r.ProxyPublicAddress == "" && r.S3BucketLocation == "") || (r.ProxyPublicAddress != "" && r.S3BucketLocation != "") { - return trace.BadParameter("provide only one of --proxy-public-url or --s3-bucket-uri") + if r.ProxyPublicAddress == "" { + return trace.BadParameter("argument --proxy-public-url is required") } - if r.ProxyPublicAddress != "" { - issuerURL, err := url.Parse(r.ProxyPublicAddress) - if err != nil { - return trace.BadParameter("--proxy-public-url is not a valid url: %v", err) - } - r.issuer = issuerURL.Host - if issuerURL.Port() == "443" { - r.issuer = issuerURL.Hostname() - } - r.issuerURL = issuerURL.String() + issuerURL, err := url.Parse(r.ProxyPublicAddress) + if err != nil { + return trace.BadParameter("--proxy-public-url is not a valid url: %v", err) } - - if r.S3BucketLocation != "" { - s3BucketURL, err := url.Parse(r.S3BucketLocation) - if err != nil || s3BucketURL.Scheme != "s3" { - return trace.BadParameter("--s3-bucket-uri must be valid s3 uri (eg s3://bucket/prefix)") - } - r.s3Bucket = s3BucketURL.Host - r.s3BucketPrefix = strings.TrimPrefix(s3BucketURL.Path, "/") - - r.issuer = fmt.Sprintf("%s.s3.amazonaws.com/%s", r.s3Bucket, r.s3BucketPrefix) - r.issuerURL = "https://" + r.issuer - - if len(r.S3JWKSContentsB64) == 0 { - return trace.BadParameter("--s3-jwks-base64 is required.") - } - r.jwksFileContents, err = base64.StdEncoding.DecodeString(r.S3JWKSContentsB64) - if err != nil { - return trace.BadParameter("--s3-jwks-base64 is invalid: %v", err) - } + r.issuer = issuerURL.Host + if issuerURL.Port() == "443" { + r.issuer = issuerURL.Hostname() } + r.issuerURL = issuerURL.String() r.ownershipTags = tags.DefaultResourceCreationTags(r.Cluster, r.IntegrationName) @@ -160,17 +108,6 @@ func (r *IdPIAMConfigureRequest) CheckAndSetDefaults() error { // IdPIAMConfigureClient describes the required methods to create the AWS OIDC IdP and a Role that trusts that identity provider. // There is no guarantee that the client is thread safe. type IdPIAMConfigureClient interface { - // SetAWSRegion sets the aws region that must be used. - // This is particularly relevant for API calls that must target a specific region's endpoint. - // Eg calling S3 APIs for buckets that are in another region. - SetAWSRegion(string) - - // RegionForCreateBucket is the AWS Region that should be used to create buckets. - RegionForCreateBucket() string - - // HTTPHead performs an HTTP request for the URL using the HEAD verb. - HTTPHead(ctx context.Context, url string) (resp *http.Response, err error) - // GetCallerIdentity returns information about the caller identity. GetCallerIdentity(ctx context.Context, params *sts.GetCallerIdentityInput, optFns ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error) @@ -188,18 +125,6 @@ type IdPIAMConfigureClient interface { // UpdateAssumeRolePolicy updates the policy that grants an IAM entity permission to assume a role. // This is typically referred to as the "role trust policy". UpdateAssumeRolePolicy(ctx context.Context, params *iam.UpdateAssumeRolePolicyInput, optFns ...func(*iam.Options)) (*iam.UpdateAssumeRolePolicyOutput, error) - - // CreateBucket creates an Amazon S3 bucket. - CreateBucket(ctx context.Context, params *s3.CreateBucketInput, optFns ...func(*s3.Options)) (*s3.CreateBucketOutput, error) - - // PutObject adds an object to a bucket. - PutObject(ctx context.Context, params *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) - - // HeadBucket checks if a bucket exists and if you have permission to access it. - HeadBucket(ctx context.Context, params *s3.HeadBucketInput, optFns ...func(*s3.Options)) (*s3.HeadBucketOutput, error) - - // DeletePublicAccessBlock removes the PublicAccessBlock configuration for an Amazon S3 bucket. - DeletePublicAccessBlock(ctx context.Context, params *s3.DeletePublicAccessBlockInput, optFns ...func(*s3.Options)) (*s3.DeletePublicAccessBlockOutput, error) } type defaultIdPIAMConfigureClient struct { @@ -208,7 +133,6 @@ type defaultIdPIAMConfigureClient struct { *iam.Client awsConfig aws.Config stsClient *sts.Client - s3Client *s3.Client } // GetCallerIdentity returns details about the IAM user or role whose credentials are used to call the operation. @@ -216,63 +140,6 @@ func (d *defaultIdPIAMConfigureClient) GetCallerIdentity(ctx context.Context, pa return d.stsClient.GetCallerIdentity(ctx, params, optFns...) } -// CreateBucket creates an Amazon S3 bucket. -func (d *defaultIdPIAMConfigureClient) CreateBucket(ctx context.Context, params *s3.CreateBucketInput, optFns ...func(*s3.Options)) (*s3.CreateBucketOutput, error) { - return d.s3Client.CreateBucket(ctx, params, optFns...) -} - -// PutObject adds an object to a bucket. -func (d *defaultIdPIAMConfigureClient) PutObject(ctx context.Context, params *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) { - return d.s3Client.PutObject(ctx, params, optFns...) -} - -// HeadBucket adds an object to a bucket. -func (d *defaultIdPIAMConfigureClient) HeadBucket(ctx context.Context, params *s3.HeadBucketInput, optFns ...func(*s3.Options)) (*s3.HeadBucketOutput, error) { - return d.s3Client.HeadBucket(ctx, params, optFns...) -} - -// PutBucketPolicy applies an Amazon S3 bucket policy to an Amazon S3 bucket. -func (d *defaultIdPIAMConfigureClient) PutBucketPolicy(ctx context.Context, params *s3.PutBucketPolicyInput, optFns ...func(*s3.Options)) (*s3.PutBucketPolicyOutput, error) { - return d.s3Client.PutBucketPolicy(ctx, params, optFns...) -} - -// DeletePublicAccessBlock removes the PublicAccessBlock configuration for an Amazon S3 bucket. -func (d *defaultIdPIAMConfigureClient) DeletePublicAccessBlock(ctx context.Context, params *s3.DeletePublicAccessBlockInput, optFns ...func(*s3.Options)) (*s3.DeletePublicAccessBlockOutput, error) { - return d.s3Client.DeletePublicAccessBlock(ctx, params, optFns...) -} - -// GetBucketPolicy returns the policy of a specified bucket -func (d *defaultIdPIAMConfigureClient) GetBucketPolicy(ctx context.Context, params *s3.GetBucketPolicyInput, optFns ...func(*s3.Options)) (*s3.GetBucketPolicyOutput, error) { - return d.s3Client.GetBucketPolicy(ctx, params, optFns...) -} - -// RegionForCreateBucket returns the region where the bucket should be created. -func (d *defaultIdPIAMConfigureClient) RegionForCreateBucket() string { - return d.awsConfig.Region -} - -// SetAWSRegion sets the aws region for next api calls. -func (d *defaultIdPIAMConfigureClient) SetAWSRegion(awsRegion string) { - if d.awsConfig.Region == awsRegion { - return - } - - d.awsConfig.Region = awsRegion - - // S3 Client is the only client that depends on the region. - d.s3Client = s3.NewFromConfig(d.awsConfig) -} - -// HTTPHead performs an HTTP request for the URL using the HEAD verb. -func (d *defaultIdPIAMConfigureClient) HTTPHead(ctx context.Context, url string) (*http.Response, error) { - req, err := http.NewRequest(http.MethodHead, url, nil) - if err != nil { - return nil, trace.Wrap(err) - } - - return d.httpClient.Do(req) -} - // NewIdPIAMConfigureClient creates a new IdPIAMConfigureClient. // The client is not thread safe. func NewIdPIAMConfigureClient(ctx context.Context) (IdPIAMConfigureClient, error) { @@ -295,13 +162,12 @@ func NewIdPIAMConfigureClient(ctx context.Context) (IdPIAMConfigureClient, error awsConfig: cfg, Client: iam.NewFromConfig(cfg), stsClient: sts.NewFromConfig(cfg), - s3Client: s3.NewFromConfig(cfg), }, nil } // ConfigureIdPIAM creates a new IAM OIDC IdP in AWS. // -// The Provider URL is Teleport's Public Address or the S3 bucket. +// The provider URL is Teleport's public address. // It also creates a new Role configured to trust the recently created IdP. // If the role already exists, it will create another trust relationship for the IdP (if it doesn't exist). // @@ -310,12 +176,6 @@ func NewIdPIAMConfigureClient(ctx context.Context) (IdPIAMConfigureClient, error // - iam:CreateRole // - iam:GetRole // - iam:UpdateAssumeRolePolicy -// -// If it's using the S3 bucket flow, the following are required as well: -// - s3:CreateBucket -// - s3:PutBucketPublicAccessBlock (used for s3:DeletePublicAccessBlock) -// - s3:ListBuckets (used for s3:HeadBucket) -// - s3:PutObject func ConfigureIdPIAM(ctx context.Context, clt IdPIAMConfigureClient, req IdPIAMConfigureRequest) error { if err := req.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) @@ -339,51 +199,13 @@ func ConfigureIdPIAM(ctx context.Context, clt IdPIAMConfigureClient, req IdPIAMC return trace.Wrap(err) } - // Configuration stops here if there's no S3 bucket. - // It will use the teleport's public address as IdP issuer. - if req.s3Bucket == "" { - return nil - } - log := slog.With( - "bucket", req.s3Bucket, - "bucket-prefix", req.s3BucketPrefix, - ) - - log.InfoContext(ctx, "Creating bucket in region", "region", clt.RegionForCreateBucket()) - if err := ensureBucketIdPIAM(ctx, clt, req, log); err != nil { - return trace.Wrap(err) - } - - log.InfoContext(ctx, `Removing "Block all public access".`) - _, err := clt.DeletePublicAccessBlock(ctx, &s3.DeletePublicAccessBlockInput{ - Bucket: &req.s3Bucket, - ExpectedBucketOwner: &req.AccountID, - }) - if err != nil { - return trace.Wrap(err) - } - - log.InfoContext(ctx, "Uploading 'openid-configuration' and 'jwks' files.") - if err := uploadOpenIDPublicFiles(ctx, clt, req); err != nil { - return trace.Wrap(err) - } - return nil } func ensureOIDCIdPIAM(ctx context.Context, clt IdPIAMConfigureClient, req IdPIAMConfigureRequest) error { - var err error - // For S3 bucket setups the thumbprint is ignored, but the API still requires a parseable one. - // https://github.com/aws-actions/configure-aws-credentials/issues/357#issuecomment-1626357333 - // We pass this dummy one for those scenarios. - thumbprint := "afafafafafafafafafafafafafafafafafafafaf" - - // For set ups that use the ProxyPublicAddress, we still calculate the thumbprint. - if req.ProxyPublicAddress != "" { - thumbprint, err = ThumbprintIdP(ctx, req.ProxyPublicAddress) - if err != nil { - return trace.Wrap(err) - } + thumbprint, err := ThumbprintIdP(ctx, req.ProxyPublicAddress) + if err != nil { + return trace.Wrap(err) } _, err = clt.CreateOpenIDConnectProvider(ctx, &iam.CreateOpenIDConnectProviderInput{ @@ -404,79 +226,6 @@ func ensureOIDCIdPIAM(ctx context.Context, clt IdPIAMConfigureClient, req IdPIAM return nil } -func ensureBucketIdPIAM(ctx context.Context, clt IdPIAMConfigureClient, req IdPIAMConfigureRequest, log *slog.Logger) error { - // According to https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html - // s3:GetBucketLocation is not recommended, and should be replaced by s3:HeadBucket according to AWS docs. - // The issue with using s3:HeadBucket is that it returns an error if the SDK client's region is not the same as the bucket. - // Doing a HEAD HTTP request seems to be the best option - resp, err := clt.HTTPHead(ctx, fmt.Sprintf("https://s3.amazonaws.com/%s", req.s3Bucket)) - if err != nil { - return trace.Wrap(err) - } - defer resp.Body.Close() - - // Even if the bucket is private, the "x-amz-bucket-region" Header will be there. - bucketRegion := resp.Header.Get("x-amz-bucket-region") - if bucketRegion != "" { - if bucketRegion == "EU" { - bucketRegion = "eu-west-1" - } - - clt.SetAWSRegion(bucketRegion) - } - - headBucketResp, err := clt.HeadBucket(ctx, &s3.HeadBucketInput{ - Bucket: &req.s3Bucket, - ExpectedBucketOwner: &req.AccountID, - }) - if err == nil { - log.InfoContext(ctx, "Bucket already exists in region", "region", aws.ToString(headBucketResp.BucketRegion)) - return nil - } - awsErr := awslib.ConvertIAMv2Error(err) - if trace.IsNotFound(awsErr) { - _, err := clt.CreateBucket(ctx, &s3.CreateBucketInput{ - Bucket: &req.s3Bucket, - CreateBucketConfiguration: awsutil.CreateBucketConfiguration(clt.RegionForCreateBucket()), - ObjectOwnership: s3types.ObjectOwnershipBucketOwnerPreferred, - }) - return trace.Wrap(err) - } - - return trace.Wrap(awsErr) -} - -func uploadOpenIDPublicFiles(ctx context.Context, clt IdPIAMConfigureClient, req IdPIAMConfigureRequest) error { - openidConfigPath := path.Join(req.s3BucketPrefix, ".well-known/openid-configuration") - jwksBucketPath := path.Join(req.s3BucketPrefix, ".well-known/jwks") - jwksPublicURI, err := url.JoinPath(req.issuerURL, ".well-known/jwks") - if err != nil { - return trace.Wrap(err) - } - - openIDConfigJSON, err := json.Marshal(oidc.OpenIDConfigurationForIssuer(req.issuer, jwksPublicURI)) - if err != nil { - return trace.Wrap(err) - } - _, err = clt.PutObject(ctx, &s3.PutObjectInput{ - Bucket: &req.s3Bucket, - Key: &openidConfigPath, - Body: bytes.NewReader(openIDConfigJSON), - ACL: s3types.ObjectCannedACLPublicRead, - }) - if err != nil { - return trace.Wrap(err) - } - - _, err = clt.PutObject(ctx, &s3.PutObjectInput{ - Bucket: &req.s3Bucket, - Key: &jwksBucketPath, - Body: bytes.NewReader(req.jwksFileContents), - ACL: s3types.ObjectCannedACLPublicRead, - }) - return trace.Wrap(err) -} - func createIdPIAMRole(ctx context.Context, clt IdPIAMConfigureClient, req IdPIAMConfigureRequest) error { integrationRoleAssumeRoleDocument, err := awslib.NewPolicyDocument( awslib.StatementForAWSOIDCRoleTrustRelationship(req.AccountID, req.issuer, []string{types.IntegrationAWSOIDCAudience}), diff --git a/lib/integrations/awsoidc/idp_iam_config_test.go b/lib/integrations/awsoidc/idp_iam_config_test.go index 9b5b10d9bd7a0..4ae10d979c73b 100644 --- a/lib/integrations/awsoidc/idp_iam_config_test.go +++ b/lib/integrations/awsoidc/idp_iam_config_test.go @@ -20,9 +20,7 @@ package awsoidc import ( "context" - "encoding/base64" "fmt" - "net/http" "net/http/httptest" "net/url" "slices" @@ -32,7 +30,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" iamTypes "github.com/aws/aws-sdk-go-v2/service/iam/types" - "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/gravitational/trace" "github.com/stretchr/testify/require" @@ -42,19 +39,7 @@ import ( ) func TestIdPIAMConfigReqDefaults(t *testing.T) { - base64EncodedString := base64.StdEncoding.EncodeToString([]byte(`jwks`)) - - baseIdPIAMConfigReqWithS3Bucket := func() IdPIAMConfigureRequest { - return IdPIAMConfigureRequest{ - Cluster: "mycluster", - IntegrationName: "myintegration", - IntegrationRole: "integrationrole", - S3BucketLocation: "s3://bucket-1/prefix-2", - S3JWKSContentsB64: base64EncodedString, - } - } - - baseIdPIAMConfigReqWithProxy := func() IdPIAMConfigureRequest { + baseIdPIAMConfigReq := func() IdPIAMConfigureRequest { return IdPIAMConfigureRequest{ Cluster: "mycluster", IntegrationName: "myintegration", @@ -70,8 +55,8 @@ func TestIdPIAMConfigReqDefaults(t *testing.T) { expected IdPIAMConfigureRequest }{ { - name: "proxy mode: set defaults", - req: baseIdPIAMConfigReqWithProxy, + name: "set defaults", + req: baseIdPIAMConfigReq, errCheck: require.NoError, expected: IdPIAMConfigureRequest{ Cluster: "mycluster", @@ -88,85 +73,18 @@ func TestIdPIAMConfigReqDefaults(t *testing.T) { }, }, { - name: "proxy mode: missing proxy public address", + name: "missing proxy public address", req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithProxy() + req := baseIdPIAMConfigReq() req.ProxyPublicAddress = "" return req }, errCheck: badParameterCheck, }, - { - name: "s3 bucket mode: set defaults", - req: baseIdPIAMConfigReqWithS3Bucket, - errCheck: require.NoError, - expected: IdPIAMConfigureRequest{ - Cluster: "mycluster", - IntegrationName: "myintegration", - IntegrationRole: "integrationrole", - S3BucketLocation: "s3://bucket-1/prefix-2", - s3Bucket: "bucket-1", - s3BucketPrefix: "prefix-2", - jwksFileContents: []byte(`jwks`), - S3JWKSContentsB64: base64EncodedString, - issuer: "bucket-1.s3.amazonaws.com/prefix-2", - issuerURL: "https://bucket-1.s3.amazonaws.com/prefix-2", - ownershipTags: tags.AWSTags{ - "teleport.dev/cluster": "mycluster", - "teleport.dev/integration": "myintegration", - "teleport.dev/origin": "integration_awsoidc", - }, - }, - }, - { - name: "s3 bucket mode: missing jwks content", - req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithS3Bucket() - req.S3JWKSContentsB64 = "" - return req - }, - errCheck: badParameterCheck, - }, - { - name: "s3 bucket mode: invalid jwks content", - req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithS3Bucket() - req.S3JWKSContentsB64 = "x" - return req - }, - errCheck: badParameterCheck, - }, - { - name: "s3 bucket mode: invalid url for s3 location", - req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithS3Bucket() - req.S3BucketLocation = "invalid-url" - return req - }, - errCheck: badParameterCheck, - }, - { - name: "s3 bucket mode: invalid schema for s3 location", - req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithS3Bucket() - req.S3BucketLocation = "https://proxy.example.com" - return req - }, - errCheck: badParameterCheck, - }, - { - name: "proxy and s3 bucket defined", - req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithProxy() - req.S3BucketLocation = "s3://bucket/prefix" - return req - }, - errCheck: badParameterCheck, - }, { name: "missing cluster", req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithProxy() + req := baseIdPIAMConfigReq() req.Cluster = "" return req }, @@ -175,7 +93,7 @@ func TestIdPIAMConfigReqDefaults(t *testing.T) { { name: "missing integration name", req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithProxy() + req := baseIdPIAMConfigReq() req.IntegrationName = "" return req }, @@ -184,7 +102,7 @@ func TestIdPIAMConfigReqDefaults(t *testing.T) { { name: "missing integration role", req: func() IdPIAMConfigureRequest { - req := baseIdPIAMConfigReqWithProxy() + req := baseIdPIAMConfigReq() req.IntegrationRole = "" return req }, @@ -230,357 +148,148 @@ func assumeRoleStatementJSON(issuer string) string { }`, issuer, issuer) } -func TestConfigureIdPIAMUsingProxyURL(t *testing.T) { +func TestConfigureIdPIAM(t *testing.T) { ctx := context.Background() - t.Run("using proxy url", func(t *testing.T) { - tlsServer := httptest.NewTLSServer(nil) - tlsServerURL, err := url.Parse(tlsServer.URL) - require.NoError(t, err) + tlsServer := httptest.NewTLSServer(nil) + tlsServerURL, err := url.Parse(tlsServer.URL) + require.NoError(t, err) - tlsServerIssuer := tlsServerURL.Host - // TLS Server starts with self-signed certificates. + tlsServerIssuer := tlsServerURL.Host + // TLS Server starts with self-signed certificates. - lib.SetInsecureDevMode(true) - defer lib.SetInsecureDevMode(false) + lib.SetInsecureDevMode(true) + defer lib.SetInsecureDevMode(false) - baseIdPIAMConfigReqWithTLServer := func() IdPIAMConfigureRequest { - return IdPIAMConfigureRequest{ - Cluster: "mycluster", - IntegrationName: "myintegration", - IntegrationRole: "integrationrole", - ProxyPublicAddress: tlsServer.URL, - } + baseIdPIAMConfigReqWithTLServer := func() IdPIAMConfigureRequest { + return IdPIAMConfigureRequest{ + Cluster: "mycluster", + IntegrationName: "myintegration", + IntegrationRole: "integrationrole", + ProxyPublicAddress: tlsServer.URL, } + } - for _, tt := range []struct { - name string - mockAccountID string - mockExistingRoles map[string]mockRole - mockExistingIdPUrl []string - req func() IdPIAMConfigureRequest - errCheck require.ErrorAssertionFunc - externalStateCheck func(*testing.T, mockIdPIAMConfigClient) - }{ - { - name: "valid", - mockAccountID: "123456789012", - req: baseIdPIAMConfigReqWithTLServer, - mockExistingIdPUrl: []string{}, - mockExistingRoles: map[string]mockRole{}, - errCheck: require.NoError, - }, - { - name: "idp url already exists", - mockAccountID: "123456789012", - mockExistingIdPUrl: []string{tlsServer.URL}, - mockExistingRoles: map[string]mockRole{}, - req: baseIdPIAMConfigReqWithTLServer, - errCheck: require.NoError, - }, - { - name: "role exists, no ownership tags", - mockAccountID: "123456789012", - mockExistingIdPUrl: []string{}, - mockExistingRoles: map[string]mockRole{"integrationrole": {}}, - req: baseIdPIAMConfigReqWithTLServer, - errCheck: badParameterCheck, - }, - { - name: "role exists, ownership tags, no assume role", - mockAccountID: "123456789012", - mockExistingIdPUrl: []string{}, - mockExistingRoles: map[string]mockRole{"integrationrole": { - tags: []iamTypes.Tag{ - {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, - {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, - {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, - }, - assumeRolePolicyDoc: aws.String(`{"Version":"2012-10-17", "Statements":[]}`), - }}, - req: baseIdPIAMConfigReqWithTLServer, - errCheck: require.NoError, - externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { - role := mipc.existingRoles["integrationrole"] - expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( - assumeRoleStatementJSON(tlsServerIssuer), - ) - require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) + for _, tt := range []struct { + name string + mockAccountID string + mockExistingRoles map[string]mockRole + mockExistingIdPUrl []string + req func() IdPIAMConfigureRequest + errCheck require.ErrorAssertionFunc + externalStateCheck func(*testing.T, mockIdPIAMConfigClient) + }{ + { + name: "valid", + mockAccountID: "123456789012", + req: baseIdPIAMConfigReqWithTLServer, + mockExistingIdPUrl: []string{}, + mockExistingRoles: map[string]mockRole{}, + errCheck: require.NoError, + }, + { + name: "idp url already exists", + mockAccountID: "123456789012", + mockExistingIdPUrl: []string{tlsServer.URL}, + mockExistingRoles: map[string]mockRole{}, + req: baseIdPIAMConfigReqWithTLServer, + errCheck: require.NoError, + }, + { + name: "role exists, no ownership tags", + mockAccountID: "123456789012", + mockExistingIdPUrl: []string{}, + mockExistingRoles: map[string]mockRole{"integrationrole": {}}, + req: baseIdPIAMConfigReqWithTLServer, + errCheck: badParameterCheck, + }, + { + name: "role exists, ownership tags, no assume role", + mockAccountID: "123456789012", + mockExistingIdPUrl: []string{}, + mockExistingRoles: map[string]mockRole{"integrationrole": { + tags: []iamTypes.Tag{ + {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, + {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, + {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, }, + assumeRolePolicyDoc: aws.String(`{"Version":"2012-10-17", "Statements":[]}`), + }}, + req: baseIdPIAMConfigReqWithTLServer, + errCheck: require.NoError, + externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { + role := mipc.existingRoles["integrationrole"] + expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( + assumeRoleStatementJSON(tlsServerIssuer), + ) + require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) }, - { - name: "role exists, ownership tags, with existing assume role", - mockAccountID: "123456789012", - mockExistingIdPUrl: []string{}, - mockExistingRoles: map[string]mockRole{"integrationrole": { - tags: []iamTypes.Tag{ - {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, - {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, - {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, - }, - assumeRolePolicyDoc: policyDocWithStatementsJSON( - assumeRoleStatementJSON("some-other-issuer"), - ), - }}, - req: baseIdPIAMConfigReqWithTLServer, - errCheck: require.NoError, - externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { - role := mipc.existingRoles["integrationrole"] - expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( - assumeRoleStatementJSON("some-other-issuer"), - assumeRoleStatementJSON(tlsServerIssuer), - ) - require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) + }, + { + name: "role exists, ownership tags, with existing assume role", + mockAccountID: "123456789012", + mockExistingIdPUrl: []string{}, + mockExistingRoles: map[string]mockRole{"integrationrole": { + tags: []iamTypes.Tag{ + {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, + {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, + {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, }, + assumeRolePolicyDoc: policyDocWithStatementsJSON( + assumeRoleStatementJSON("some-other-issuer"), + ), + }}, + req: baseIdPIAMConfigReqWithTLServer, + errCheck: require.NoError, + externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { + role := mipc.existingRoles["integrationrole"] + expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( + assumeRoleStatementJSON("some-other-issuer"), + assumeRoleStatementJSON(tlsServerIssuer), + ) + require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) }, - { - name: "role exists, ownership tags, assume role already exists", - mockAccountID: "123456789012", - mockExistingIdPUrl: []string{}, - mockExistingRoles: map[string]mockRole{"integrationrole": { - tags: []iamTypes.Tag{ - {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, - {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, - {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, - }, - assumeRolePolicyDoc: policyDocWithStatementsJSON( - assumeRoleStatementJSON(tlsServerIssuer), - ), - }}, - req: baseIdPIAMConfigReqWithTLServer, - errCheck: require.NoError, - externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { - role := mipc.existingRoles["integrationrole"] - expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( - assumeRoleStatementJSON(tlsServerIssuer), - ) - require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) + }, + { + name: "role exists, ownership tags, assume role already exists", + mockAccountID: "123456789012", + mockExistingIdPUrl: []string{}, + mockExistingRoles: map[string]mockRole{"integrationrole": { + tags: []iamTypes.Tag{ + {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, + {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, + {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, }, + assumeRolePolicyDoc: policyDocWithStatementsJSON( + assumeRoleStatementJSON(tlsServerIssuer), + ), + }}, + req: baseIdPIAMConfigReqWithTLServer, + errCheck: require.NoError, + externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { + role := mipc.existingRoles["integrationrole"] + expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( + assumeRoleStatementJSON(tlsServerIssuer), + ) + require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) }, - } { - t.Run(tt.name, func(t *testing.T) { - clt := mockIdPIAMConfigClient{ - accountID: tt.mockAccountID, - existingRoles: tt.mockExistingRoles, - existingIDPUrl: tt.mockExistingIdPUrl, - } - - err := ConfigureIdPIAM(ctx, &clt, tt.req()) - tt.errCheck(t, err) - - if tt.externalStateCheck != nil { - tt.externalStateCheck(t, clt) - } - }) - } - }) - - t.Run("using s3 bucket", func(t *testing.T) { - base64EncodedString := base64.StdEncoding.EncodeToString([]byte(`jwks`)) - - baseIdPIAMConfigReqWithS3Bucket := func() IdPIAMConfigureRequest { - return IdPIAMConfigureRequest{ - Cluster: "mycluster", - IntegrationName: "myintegration", - IntegrationRole: "integrationrole", - S3BucketLocation: "s3://bucket-1/prefix-2", - S3JWKSContentsB64: base64EncodedString, + }, + } { + t.Run(tt.name, func(t *testing.T) { + clt := mockIdPIAMConfigClient{ + accountID: tt.mockAccountID, + existingRoles: tt.mockExistingRoles, + existingIDPUrl: tt.mockExistingIdPUrl, } - } - expectedIssuer := "bucket-1.s3.amazonaws.com/prefix-2" - expectedIssuerURL := "https://" + expectedIssuer - - for _, tt := range []struct { - name string - mockAccountID string - mockExistingIdPUrl []string - mockExistingRoles map[string]mockRole - mockClientRegion string - mockExistingBuckets map[string]mockBucket - req func() IdPIAMConfigureRequest - errCheck require.ErrorAssertionFunc - externalStateCheck func(*testing.T, mockIdPIAMConfigClient) - }{ - { - name: "valid without any existing resources", - mockAccountID: "123456789012", - req: baseIdPIAMConfigReqWithS3Bucket, - mockExistingIdPUrl: []string{}, - mockExistingRoles: map[string]mockRole{}, - mockExistingBuckets: map[string]mockBucket{}, - mockClientRegion: "my-region", - errCheck: require.NoError, - externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { - // Check IdP creation - require.Contains(t, mipc.existingIDPUrl, expectedIssuerURL) - - // Check Role creation - role := mipc.existingRoles["integrationrole"] - expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( - assumeRoleStatementJSON(expectedIssuer), - ) - require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) - - // Check Bucket creation - require.Contains(t, mipc.existingBuckets, "bucket-1") - bucket := mipc.existingBuckets["bucket-1"] - require.Equal(t, "my-region", bucket.region) - require.False(t, bucket.publicAccessIsBlocked) - require.Equal(t, "BucketOwnerPreferred", bucket.ownership) - - jwksKey := "bucket-1/prefix-2/.well-known/jwks" - require.Contains(t, mipc.existingObjects, jwksKey) - require.Equal(t, "public-read", mipc.existingObjects[jwksKey].acl) - - openidconfigKey := "bucket-1/prefix-2/.well-known/openid-configuration" - require.Contains(t, mipc.existingObjects, openidconfigKey) - require.Equal(t, "public-read", mipc.existingObjects[openidconfigKey].acl) - }, - }, - { - name: "valid with an existing IdP set up using Proxy URL", - mockAccountID: "123456789012", - req: baseIdPIAMConfigReqWithS3Bucket, - mockExistingIdPUrl: []string{"https://proxy.example.com"}, - mockExistingRoles: map[string]mockRole{ - "integrationrole": { - tags: []iamTypes.Tag{ - {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, - {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, - {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, - }, - assumeRolePolicyDoc: policyDocWithStatementsJSON( - assumeRoleStatementJSON("proxy.example.com"), - ), - }, - }, - mockExistingBuckets: map[string]mockBucket{}, - mockClientRegion: "my-region", - errCheck: require.NoError, - externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { - // IdP should be created and the existing one must not be deleted. - require.Contains(t, mipc.existingIDPUrl, expectedIssuerURL) - require.Contains(t, mipc.existingIDPUrl, "https://proxy.example.com") - - // The role must include the new statement and must not delete the previous one - role := mipc.existingRoles["integrationrole"] - expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( - assumeRoleStatementJSON("proxy.example.com"), - assumeRoleStatementJSON(expectedIssuer), - ) - require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) - - // Check Bucket creation - require.Contains(t, mipc.existingBuckets, "bucket-1") - bucket := mipc.existingBuckets["bucket-1"] - require.Equal(t, "my-region", bucket.region) - require.False(t, bucket.publicAccessIsBlocked) - require.Equal(t, "BucketOwnerPreferred", bucket.ownership) - }, - }, - { - name: "bucket already exists but is on another region", - mockAccountID: "123456789012", - req: baseIdPIAMConfigReqWithS3Bucket, - mockExistingIdPUrl: []string{}, - mockExistingRoles: map[string]mockRole{}, - mockExistingBuckets: map[string]mockBucket{ - "bucket-1": { - region: "another-region", - publicAccessIsBlocked: true, - ownership: "BucketOwnerPreferred", - }, - }, - mockClientRegion: "my-region", - errCheck: require.NoError, - externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { - // Check IdP creation - require.Contains(t, mipc.existingIDPUrl, expectedIssuerURL) - - // Check Role creation - role := mipc.existingRoles["integrationrole"] - expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( - assumeRoleStatementJSON(expectedIssuer), - ) - require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) - - // Check Bucket creation - require.Contains(t, mipc.existingBuckets, "bucket-1") - bucket := mipc.existingBuckets["bucket-1"] - require.False(t, bucket.publicAccessIsBlocked) - require.Equal(t, "BucketOwnerPreferred", bucket.ownership) - - // The last configured region must be the existing bucket's region. - require.Equal(t, "another-region", mipc.clientRegion) - }, - }, - { - name: "everything already exists", - mockAccountID: "123456789012", - req: baseIdPIAMConfigReqWithS3Bucket, - mockExistingIdPUrl: []string{"https://bucket-1.s3.amazonaws.com/prefix-2"}, - mockExistingRoles: map[string]mockRole{ - "integrationrole": { - tags: []iamTypes.Tag{ - {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, - {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, - {Key: aws.String("teleport.dev/integration"), Value: aws.String("myintegration")}, - }, - assumeRolePolicyDoc: policyDocWithStatementsJSON( - assumeRoleStatementJSON("bucket-1.s3.amazonaws.com/prefix-2"), - ), - }, - }, - mockExistingBuckets: map[string]mockBucket{ - "bucket-1": { - region: "my-region", - publicAccessIsBlocked: true, - }, - }, - mockClientRegion: "my-region", - errCheck: require.NoError, - externalStateCheck: func(t *testing.T, mipc mockIdPIAMConfigClient) { - // Check IdP exists - require.Contains(t, mipc.existingIDPUrl, expectedIssuerURL) - // Check Role exists - role := mipc.existingRoles["integrationrole"] - expectedAssumeRolePolicyDoc := policyDocWithStatementsJSON( - assumeRoleStatementJSON(expectedIssuer), - ) - require.JSONEq(t, *expectedAssumeRolePolicyDoc, aws.ToString(role.assumeRolePolicyDoc)) - - // Check Bucket exists - require.Contains(t, mipc.existingBuckets, "bucket-1") - bucket := mipc.existingBuckets["bucket-1"] - require.False(t, bucket.publicAccessIsBlocked) - }, - }, - } { - t.Run(tt.name, func(t *testing.T) { - clt := mockIdPIAMConfigClient{ - accountID: tt.mockAccountID, - existingRoles: tt.mockExistingRoles, - existingIDPUrl: tt.mockExistingIdPUrl, - existingBuckets: tt.mockExistingBuckets, - clientRegion: tt.mockClientRegion, - } - - err := ConfigureIdPIAM(ctx, &clt, tt.req()) - tt.errCheck(t, err) - - if tt.externalStateCheck != nil { - tt.externalStateCheck(t, clt) - } - }) - } - }) -} + err := ConfigureIdPIAM(ctx, &clt, tt.req()) + tt.errCheck(t, err) -type mockBucket struct { - region string - publicAccessIsBlocked bool - ownership string + if tt.externalStateCheck != nil { + tt.externalStateCheck(t, clt) + } + }) + } } type mockRole struct { @@ -588,16 +297,10 @@ type mockRole struct { tags []iamTypes.Tag } -type mockObject struct { - acl string -} type mockIdPIAMConfigClient struct { - clientRegion string - accountID string - existingIDPUrl []string - existingRoles map[string]mockRole - existingBuckets map[string]mockBucket - existingObjects map[string]mockObject + accountID string + existingIDPUrl []string + existingRoles map[string]mockRole } // GetCallerIdentity returns information about the caller identity. @@ -671,95 +374,6 @@ func (m *mockIdPIAMConfigClient) UpdateAssumeRolePolicy(ctx context.Context, par return &iam.UpdateAssumeRolePolicyOutput{}, nil } -// CreateBucket creates an Amazon S3 bucket. -func (m *mockIdPIAMConfigClient) CreateBucket(ctx context.Context, params *s3.CreateBucketInput, optFns ...func(*s3.Options)) (*s3.CreateBucketOutput, error) { - m.existingBuckets[*params.Bucket] = mockBucket{ - publicAccessIsBlocked: true, - region: m.clientRegion, - ownership: string(params.ObjectOwnership), - } - return nil, nil -} - -// PutObject adds an object to a bucket. -func (m *mockIdPIAMConfigClient) PutObject(ctx context.Context, params *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) { - if m.existingObjects == nil { - m.existingObjects = map[string]mockObject{} - } - - objectKey := fmt.Sprintf("%s/%s", *params.Bucket, *params.Key) - - m.existingObjects[objectKey] = mockObject{ - acl: string(params.ACL), - } - return nil, nil -} - -// HeadBucket adds an object to a bucket. -func (m *mockIdPIAMConfigClient) HeadBucket(ctx context.Context, params *s3.HeadBucketInput, optFns ...func(*s3.Options)) (*s3.HeadBucketOutput, error) { - bucket, found := m.existingBuckets[*params.Bucket] - if !found { - return nil, trace.NotFound("bucket does not exist") - } - - return &s3.HeadBucketOutput{ - BucketRegion: &bucket.region, - }, nil -} - -// RegionForCreateBucket returns the default aws region to use when creating a bucket. -func (m *mockIdPIAMConfigClient) RegionForCreateBucket() string { - return m.clientRegion -} - -// SetAWSRegion sets the default aws region to use. -func (m *mockIdPIAMConfigClient) SetAWSRegion(awsRegion string) { - m.clientRegion = awsRegion -} - -// DeletePublicAccessBlock removes the PublicAccessBlock configuration for an Amazon S3 bucket. -func (m *mockIdPIAMConfigClient) DeletePublicAccessBlock(ctx context.Context, params *s3.DeletePublicAccessBlockInput, optFns ...func(*s3.Options)) (*s3.DeletePublicAccessBlockOutput, error) { - bucket, found := m.existingBuckets[*params.Bucket] - if !found { - return nil, trace.NotFound("bucket does not exist") - } - - bucket.publicAccessIsBlocked = false - m.existingBuckets[*params.Bucket] = bucket - - return &s3.DeletePublicAccessBlockOutput{}, nil -} - -// HTTPHead does an HEAD HTTP Request to the target URL. -func (m *mockIdPIAMConfigClient) HTTPHead(ctx context.Context, endpoint string) (*http.Response, error) { - endpointURL, err := url.Parse(endpoint) - if err != nil { - return nil, trace.Wrap(err) - } - - // check if bucket exists - // expected URL is: https://s3.amazonaws.com// - endpointURLPath := strings.TrimLeft(endpointURL.Path, "/") - bucketName := strings.Split(endpointURLPath, "/")[0] - - bucket, found := m.existingBuckets[bucketName] - if !found { - return &http.Response{ - StatusCode: http.StatusNotFound, - Body: http.NoBody, - }, nil - } - - m.clientRegion = bucket.region - - return &http.Response{ - Header: http.Header{ - "x-amz-bucket-region": []string{bucket.region}, - }, - Body: http.NoBody, - }, nil -} - func TestNewIdPIAMConfigureClient(t *testing.T) { t.Run("no aws_region env var, returns an error", func(t *testing.T) { _, err := NewIdPIAMConfigureClient(context.Background()) diff --git a/tool/teleport/common/integration_configure.go b/tool/teleport/common/integration_configure.go index 27d2134e0bcf7..dab36f0a5f8b3 100644 --- a/tool/teleport/common/integration_configure.go +++ b/tool/teleport/common/integration_configure.go @@ -144,8 +144,6 @@ func onIntegrationConfAWSOIDCIdP(ctx context.Context, clf config.CommandLineFlag IntegrationName: clf.IntegrationConfAWSOIDCIdPArguments.Name, IntegrationRole: clf.IntegrationConfAWSOIDCIdPArguments.Role, ProxyPublicAddress: clf.IntegrationConfAWSOIDCIdPArguments.ProxyPublicURL, - S3BucketLocation: clf.IntegrationConfAWSOIDCIdPArguments.S3BucketURI, - S3JWKSContentsB64: clf.IntegrationConfAWSOIDCIdPArguments.S3JWKSContentsB64, } return trace.Wrap(awsoidc.ConfigureIdPIAM(ctx, iamClient, confReq)) } diff --git a/tool/teleport/common/teleport.go b/tool/teleport/common/teleport.go index fc96158a942e7..0f73e8caf69a6 100644 --- a/tool/teleport/common/teleport.go +++ b/tool/teleport/common/teleport.go @@ -493,13 +493,9 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con IntegrationConfAWSOIDCIdPArguments.Name) integrationConfAWSOIDCIdPCmd.Flag("role", "The AWS Role used by the AWS OIDC Integration.").Required().StringVar(&ccf. IntegrationConfAWSOIDCIdPArguments.Role) - integrationConfAWSOIDCIdPCmd.Flag("proxy-public-url", "Proxy Public URL (eg https://mytenant.teleport.sh).").StringVar(&ccf. + integrationConfAWSOIDCIdPCmd.Flag("proxy-public-url", "Proxy Public URL (eg https://mytenant.teleport.sh).").Required().StringVar(&ccf. IntegrationConfAWSOIDCIdPArguments.ProxyPublicURL) integrationConfAWSOIDCIdPCmd.Flag("insecure", "Insecure mode disables certificate validation.").BoolVar(&ccf.InsecureMode) - integrationConfAWSOIDCIdPCmd.Flag("s3-bucket-uri", "The S3 URI(format: s3:///) used to store the OpenID configuration and public keys. ").StringVar(&ccf. - IntegrationConfAWSOIDCIdPArguments.S3BucketURI) - integrationConfAWSOIDCIdPCmd.Flag("s3-jwks-base64", `The JWKS base 64 encoded. Required when using the S3 Bucket as the Issuer URL. Format: base64({"keys":[{"kty":"RSA","alg":"RS256","n":"","e":"","use":"sig","kid":""}]}).`).StringVar(&ccf. - IntegrationConfAWSOIDCIdPArguments.S3JWKSContentsB64) integrationConfListDatabasesCmd := integrationConfigureCmd.Command("listdatabases-iam", "Adds required IAM permissions to List RDS Databases (Instances and Clusters).") integrationConfListDatabasesCmd.Flag("aws-region", "AWS Region.").Required().StringVar(&ccf.IntegrationConfListDatabasesIAMArguments.Region)