From 82020390a9a91f53d142c6f3546052c9719d43f1 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Thu, 2 Mar 2023 19:25:51 +0000 Subject: [PATCH 01/14] first draft --- ...999-oidc-idp-for-aws-resource-discovery.md | 463 ++++++++++++++++++ 1 file changed, 463 insertions(+) create mode 100644 rfd/9999-oidc-idp-for-aws-resource-discovery.md diff --git a/rfd/9999-oidc-idp-for-aws-resource-discovery.md b/rfd/9999-oidc-idp-for-aws-resource-discovery.md new file mode 100644 index 0000000000000..ff0d6b603c0d3 --- /dev/null +++ b/rfd/9999-oidc-idp-for-aws-resource-discovery.md @@ -0,0 +1,463 @@ +--- +authors: Marco Dinis (marco.dinis@goteleport.com) +state: draft +--- + +# RFD 999 - OIDC IdP for AWS resource discovery + +## Required Approvals + +* Engineering: @ryanclark && @r0mant +* Product: @xinding33 || @klizhentas +* Security: @reedloden + +## What + +Discover AWS resources without manual configuration. + +#### Goals + +Easily discover AWS RDS Databases of an account. + +#### Non-goals + +Having a real OIDC IdP is out of scope. +That initiative can be tracked [here](https://github.com/gravitational/teleport/issues/20967). + +Automatically onboard AWS RDS Databases into Teleport. + +## Terminology + +* OIDC: OpenID Connect is a protocol that works on top of OAuth2 and provides identity information. +* IdP: Identity Provider is a system that manages identities. +* JWKS: JSON Web Key Set is a set of public keys that IdP consumers must use to validate a signed JWT. + +## Why + +Our current discovery process for AWS resources requires multiple steps before the user gets to the "aha moment". +Some of those steps are a little complicated and require the user to know some Teleport specific internals. + +We can reduce the number of steps and remove most of the Teleport specific configuration by creating an OIDC IdP in teleport. + +## How +AWS allows the set up of an IdP using OIDC providers. +Each provider has a set of roles, which limit their access. + +Turning Teleport into an OIDC IdP, and asking the user to create a new OIDC IdP that consumes the teleport OIDC endpoints, allows us to easily call AWS API endpoints to, for instance, list RDS instances and their details. + +### High Level Flow +Simplified flow of interactions between User, Teleport and AWS: + +``` + ┌─────────┐ + │ │ + ┌─────────────────────────────────────────────►│ AWS │ + 2│ │ │ + │ └──┬───▲──┘ +User────────────┤ │ │ + │ ┌───────────────────────┐ │ │ + 1│ │ Teleport │ │ │ + │ │ │ │ │ + 5│ ┌──┼──────┐ ┌────────┼──┐ │ │ + └────► │ Web │ │ OIDC │ │ 3 │ │ + └──┼──┬───┘ │ IdP │ │◄─────────────┘ │ + │ │ └┬───────┼──┘ │ + │ │ │ │ │ + │ │ 4│ │ │ + │ │ │ │ │ + │ │ ┌─────────▼┐ │ │ + │ │ │ CA KeySet│ │ │ + │ │ │ RSA Key │ │ │ + │ │ └─────────▲┘ │ │ + │ │6 │7 │ │ + │ │ ┌──────┴────┐ │ │ + │ │ │ Discover │ │ 8 │ + │ └────►│ Service ├──┼─────────────────────┘ + │ │ [ RDS ] │ │ + │ └───────────┘ │ + │ │ + └───────────────────────┘ +``` + +#### User's Point of View +When the user adds a new resource, using the Discover Wizard, they'll be asked where the resource lives. + +The flow from the user's point of view should be the following: + +1. User chooses to Add resources from AWS, and is then prompted to setup an OIDC Identity Provider pointing to its teleport instance's url. +2. User opens AWS, selects IAM and then, under `Access Management`, selects `Identity providers`. +3. Configures the Teleport instance as an OIDC IdP: + 1. Clicks `Add provider` of type `OpenID Connect`. + 2. Fills in the Provider URL as provided by the Discover Wizard. + 3. Fills in the Audience as provided by the Discover Wizard `sts.amazonaws.com`. +4. The user is then asked to enter the Thumbprint in Teleport, to ensure the user entered the correct `Provider URL`. +5. Configures the role associated with that IdP + 1. The user is asked to create or assign an existing role. + 2. The role's `Policies` must be filled with the required Policies (described down below). + 3. The role's `Trust relationships` must target the Identity Provider they just created (described down below). +6. The user will be greeted with a message saying that the configuration was successful. + +To ease the necessary manual steps, the Discover wizard will provide a small video demoing what the user must do for the previous steps. + +#### System's Point of View +As for the flow that happens automatically, we have the following: + +The first interaction between AWS and Teleport happens when the user clicks on `Get Thumbprint` (step 4 of the User's Point of View flow). +This will trigger a request started by AWS to Teleport hitting the OpenID Configuration endpoint and subsequently the JSON Web Key Set endpoint (3). + +After this step, when the user tries to list a resource (eg, RDS databases), Teleport generates a token and issues the API call. + +To generate a token, Teleport creates a JWT with the claims described above and sign it with the private key (the public is provided in the public JWKS endpoint). + +AWS receives the request and validates the token against the public key provided by OIDC IdP (ie, Teleport) at the `jwks_uri`. +If authenticated and authorized for the api call, AWS returns the response to the API call. + +### Implementation Details + +#### Signing Key +One of the requirements to be an OIDC provider is to provide the public key in a known HTTP endpoint and sign a JSON object (with claims) with the private key. + +We'll re-use the RSA key that exists to sign JWT tokens for App Access. + +#### HTTP Endpoints +We'll use two HTTP endpoints: + +##### OpenID Configuration +According to the [spec](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig) the Identity Provider must provide an endpoint at `/.well-known/openid-configuration` that returns the provider's configuration. + +So, a new endpoint at `/.well-known/openid-configuration` will be created that returns the following JSON: +``` +200 OK + +{ + "issuer": "", + "jwks_uri": "/.well-known/jwks.json", + "claims": ["iss", "sub", "aud", "jti", "iat", "exp", "nbf"], + "id_token_signing_alg_values_supported": ["RS256"], + "response_types_supported": ["id_token"], + "scopes_supported": ["openid"], + "subject_types_supported": ["public", "pairwise"] +} +``` + +- Issuer: the provider's URL +- JWKS URI: the endpoint where the provider returns the public keys. +- Claims Supported: a list of supported claims that the OpenID Provider (ie, Teleport) MAY be able to supply values for when issuing a token: + - `iss`: the issuer identity, on our case it will be the same as the `issuer` key. + - `sub`: identifies the subject of the token, on our case it will contain the user's name. + - `aud`: the audience for the token, on our case it will be the same as the `audience` defined when configuring the OIDC IdP in AWS (step 3.3 for the User's Point of View). + - `jti`: is the token id. + - `iat`: unix epoch time of when the token was issued. + - `exp`: unix epoch time of when the token is no longer valid (expired). + - `nbf`: unix epoch time which indicates when the token began to be valid. +- ID Token Signing Algorithm Values Supported: a list of supported signing algorithms to assist during token validation. +- Scopes Supported: a list of scopes to be used, on our case it will only contain the required one: `openid`. +- Subject Types Supported: a list of supported subject types: + - `public`: we can either return clear text version of the subject (user names) or + - `pairwise`: we can return a hash of the subject's identity (to hide their email, for instance) + +##### JSON Web Key Sets +This endpoint returns a list of public keys (usually only one key, except for periods of key rotation). + +This endpoint URI must be equal to `jwks_uri` defined in the previous section. + +As an example, `/.well-known/jwks.json`. + +It should return the following: + +``` +200 OK + +{ + "keys": [ + { + "kty": "RSA", + "alg": "RS256", + "n": "", + "e": "AQAB" + } + ] +} +``` + +This must respect the RFC7517 (eg of a key can be found at https://www.rfc-editor.org/rfc/rfc7517#appendix-A.1). + +We'll re-use the current endpoint located at `https:///.well-known/jwks.json`. + +#### AWS Role for Teleport OIDC IdP + +The user will create or associate a role to the Teleport OIDC IdP. +This role must have access to list RDS Databases and have that Identity Provider as a trusted policy. + +At least a policy allowing the following must be part of the role: +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "rds:DescribeDBInstances", + "Resource": "*" + } + ] +} +``` + +Trusted relationship: +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam:::oidc-provider/" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + ":aud": "sts.amazonaws.com" + } + } + } + ] +} +``` + +### Security + +#### Rotation +JWT Signging keys can be rotated using `tctl auth rotate --type=jwt`. + +JWKS endpoint returns a list of public keys, so the old and the new key are provided for a seamless migration. + +#### MITM between AWS and Teleport + +The only configuration AWS has about the provider is its URL. +If that DNS is controlled by some evil part, AWS might accept requests from that evil part. + +However, assuming the DNS is controlled by an evil part, then the users that are logging in to Teleport are also providing their credentials to that part. + +We don't think this is a scenario we should focus on this RFD. + +#### AWS Calls from unauthorized Teleport Users +We'll be able to call `DescribeDBInstances` AWS endpoint, however we must ensure that this is protected by RBAC. + +In order to do so, we'll re-use the `db` resource with the `list` verb to allow listing RDS Databases. +```yaml +kind: role +metadata: + description: Edit cluster configuration + name: editor +spec: + allow: + rules: + - resources: + - db + verbs: + - list +``` + +## Proof of Concept + +
+View code + +Check the `TODO`s within the source code. + +```golang +package main + +import ( + "crypto/rsa" + "crypto/x509" + _ "embed" + "encoding/pem" + "fmt" + "net/http" + "os" + "time" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/rds" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/go-jose/go-jose/v3" + "github.com/go-jose/go-jose/v3/jwt" + "github.com/gravitational/trace" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "github.com/olekukonko/tablewriter" +) + +type DiscoveryConfiguration struct { + // Issuer is the identifier of the OP and is used in the tokens as `iss` claim. + Issuer string `json:"issuer,omitempty"` + + // JwksURI is the URL of the JSON Web Key Set. This site contains the signing keys that RPs can use to validate the signature. + // It may also contain the OP's encryption keys that RPs can use to encrypt request to the OP. + JwksURI string `json:"jwks_uri,omitempty"` + + // ClaimsSupported contains a list of Claim Names the OP may be able to supply values for. This list might not be exhaustive. + ClaimsSupported []string `json:"claims_supported,omitempty"` + + // IDTokenSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for the ID Token. + IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"` + + // ResponseTypesSupported contains a list of the OAuth 2.0 response_type values that the OP supports (code, id_token, token id_token, ...). + ResponseTypesSupported []string `json:"response_types_supported,omitempty"` + + // ScopesSupported lists an array of supported scopes. This list must not include every supported scope by the OP. + ScopesSupported []string `json:"scopes_supported,omitempty"` + + // SubjectTypesSupported contains a list of Subject Identifier types that the OP supports (pairwise, public). + SubjectTypesSupported []string `json:"subject_types_supported,omitempty"` +} + +// $ openssl genrsa -out keypair.pem 2048 +// +//go:embed keypair.pem +var privateKey string + +// TODO replace with a public HTTPS server which serves this server (port 1323) +var URL = "/v1" +// TODO add account id and role to be associated to the IdP +var roleARN = "arn:aws:iam:::role/" + +type IdentityToken string + +// GetIdentityToken retrieves the JWT token from the file and returns the contents as a []byte +func (j IdentityToken) GetIdentityToken() ([]byte, error) { + return []byte(j), nil +} + +func main() { + e := echo.New() + e.Debug = true + e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ + Format: "method=${method}, uri=${uri}, status=${status}\n", + })) + + block, _ := pem.Decode([]byte(privateKey)) + parseResult, _ := x509.ParsePKCS8PrivateKey(block.Bytes) + key := parseResult.(*rsa.PrivateKey) + + e.GET("/v1/.well-known/openid-configuration", func(c echo.Context) error { + discovery := &DiscoveryConfiguration{ + Issuer: "https://" + URL, + JwksURI: "https://" + URL + "/.well-known/jwks", + ClaimsSupported: []string{"sub", "aud", "exp", "iat", "iss", "jti", "nbf", "ref"}, + IDTokenSigningAlgValuesSupported: []string{"RS256"}, + ResponseTypesSupported: []string{"id_token"}, + ScopesSupported: []string{"openid"}, + SubjectTypesSupported: []string{"public", "pairwise"}, + } + + return c.JSON(http.StatusOK, discovery) + }) + + e.GET("/v1/.well-known/jwks", func(c echo.Context) error { + keyset := &jose.JSONWebKeySet{ + Keys: []jose.JSONWebKey{ + { + KeyID: "id", + Algorithm: "RS256", + Use: "sig", + Key: &key.PublicKey, + }, + }, + } + + return c.JSON(http.StatusOK, keyset) + }) + + e.GET("/aws", func(c echo.Context) error { + ctx := c.Request().Context() + + key := jose.SigningKey{Algorithm: jose.RS256, Key: key} + + // create a Square.jose RSA signer, used to sign the JWT + var signerOpts = jose.SignerOptions{} + signerOpts.WithType("JWT") + rsaSigner, err := jose.NewSigner(key, &signerOpts) + if err != nil { + return trace.Wrap(err) + } + + builder := jwt.Signed(rsaSigner) + + pubClaims := jwt.Claims{ + Issuer: "https://" + URL, + Subject: "some-subject", + ID: "id1", + Audience: jwt.Audience{"sts.amazonaws.com"}, + IssuedAt: jwt.NewNumericDate(time.Now()), + Expiry: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + } + + builder = builder.Claims(pubClaims) + rawJWT, err := builder.CompactSerialize() + if err != nil { + return trace.Wrap(err) + } + + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + return trace.Wrap(err) + } + cfg.Region = "us-east-1" + + p := stscreds.NewWebIdentityRoleProvider( + sts.NewFromConfig(cfg), + roleARN, + IdentityToken(rawJWT), + ) + + cfg2, err := config.LoadDefaultConfig(ctx, config.WithCredentialsProvider(p)) + if err != nil { + return trace.Wrap(err) + } + cfg2.Region = "us-east-1" + + // RDS List DBs + rdsClient := rds.NewFromConfig(cfg2) + rdsDBs, err := rdsClient.DescribeDBInstances(ctx, &rds.DescribeDBInstancesInput{}) + if err != nil { + return trace.Wrap(err) + } + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Status", "Name", "IAMAuth", "Engine", "EngineVersion", "MasterUserName", "DBName", "Tags", "ARN", "Addr", "Port"}) + + for _, db := range rdsDBs.DBInstances { + table.Append([]string{ + *db.DBInstanceStatus, + *db.DBInstanceIdentifier, + fmt.Sprintf("%t", db.IAMDatabaseAuthenticationEnabled), + *db.Engine, + *db.EngineVersion, + *db.MasterUsername, + stringOrNil(db.DBName), + fmt.Sprintf("%v", db.TagList), + *db.DBInstanceArn, + *db.Endpoint.Address, + fmt.Sprintf("%d", db.Endpoint.Port), + }) + } + table.Render() // Send output + + return c.String(http.StatusOK, "hello!") + }) + + e.Logger.Fatal(e.Start(":1323")) +} + +func stringOrNil(s *string) string { + if s == nil { + return "" + } + return *s +} +``` +
From 211d614b4a043c11f9495108437f9dbc22ceefd6 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Fri, 3 Mar 2023 17:17:27 +0000 Subject: [PATCH 02/14] integration resource and new key for oidc --- ...999-oidc-idp-for-aws-rds-dbs-discovery.md} | 82 +++++++++++++------ 1 file changed, 57 insertions(+), 25 deletions(-) rename rfd/{9999-oidc-idp-for-aws-resource-discovery.md => 9999-oidc-idp-for-aws-rds-dbs-discovery.md} (86%) diff --git a/rfd/9999-oidc-idp-for-aws-resource-discovery.md b/rfd/9999-oidc-idp-for-aws-rds-dbs-discovery.md similarity index 86% rename from rfd/9999-oidc-idp-for-aws-resource-discovery.md rename to rfd/9999-oidc-idp-for-aws-rds-dbs-discovery.md index ff0d6b603c0d3..5ea069decd63b 100644 --- a/rfd/9999-oidc-idp-for-aws-resource-discovery.md +++ b/rfd/9999-oidc-idp-for-aws-rds-dbs-discovery.md @@ -3,7 +3,7 @@ authors: Marco Dinis (marco.dinis@goteleport.com) state: draft --- -# RFD 999 - OIDC IdP for AWS resource discovery +# RFD 999 - OIDC IdP for AWS RDS DBs discovery ## Required Approvals @@ -13,7 +13,7 @@ state: draft ## What -Discover AWS resources without manual configuration. +Discover AWS RDS Databases without manual configuration. #### Goals @@ -26,10 +26,13 @@ That initiative can be tracked [here](https://github.com/gravitational/teleport/ Automatically onboard AWS RDS Databases into Teleport. +Discovering other AWS resources is out of scope. + ## Terminology * OIDC: OpenID Connect is a protocol that works on top of OAuth2 and provides identity information. * IdP: Identity Provider is a system that manages identities. +* JWT: JSON Web Token is a json encoded token that contains a set of claims signed by an entity. * JWKS: JSON Web Key Set is a set of public keys that IdP consumers must use to validate a signed JWT. ## Why @@ -37,13 +40,29 @@ Automatically onboard AWS RDS Databases into Teleport. Our current discovery process for AWS resources requires multiple steps before the user gets to the "aha moment". Some of those steps are a little complicated and require the user to know some Teleport specific internals. -We can reduce the number of steps and remove most of the Teleport specific configuration by creating an OIDC IdP in teleport. +We can reduce the number of steps and remove most of the Teleport specific configuration by creating an OIDC IdP in Teleport. ## How -AWS allows the set up of an IdP using OIDC providers. + +AWS allows the [set up](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) of an IdP using OIDC providers. Each provider has a set of roles, which limit their access. -Turning Teleport into an OIDC IdP, and asking the user to create a new OIDC IdP that consumes the teleport OIDC endpoints, allows us to easily call AWS API endpoints to, for instance, list RDS instances and their details. +Turning Teleport into an OIDC IdP, and asking the user to create a new OIDC IdP that consumes the Teleport OIDC endpoints, allows us to easily call AWS API endpoints to, for instance, list RDS instances and their details. + +When configuring the provider, we'll need an AWS Role which Teleport uses to issue API Calls. + +To store the configuration above, we'll create a new resource Kind: `Integration`. +It'll leverage the `subkind` prop to distinguish future integrations. + +```yaml +kind: integration +subkind: aws-oidc +version: v1 +metadata: + name: some-name +spec: + aws_role: +``` ### High Level Flow Simplified flow of interactions between User, Teleport and AWS: @@ -67,7 +86,7 @@ User────────────┤ │ │ │ │ │ │ │ ┌─────────▼┐ │ │ │ │ │ CA KeySet│ │ │ - │ │ │ RSA Key │ │ │ + │ │ │ +RSA Key │ │ │ │ │ └─────────▲┘ │ │ │ │6 │7 │ │ │ │ ┌──────┴────┐ │ │ @@ -81,10 +100,9 @@ User────────────┤ #### User's Point of View When the user adds a new resource, using the Discover Wizard, they'll be asked where the resource lives. +Choosing an RDS DB, the user is presented with the following flow: -The flow from the user's point of view should be the following: - -1. User chooses to Add resources from AWS, and is then prompted to setup an OIDC Identity Provider pointing to its teleport instance's url. +1. User is prompted to setup an OIDC Identity Provider pointing to its Teleport instance's url. 2. User opens AWS, selects IAM and then, under `Access Management`, selects `Identity providers`. 3. Configures the Teleport instance as an OIDC IdP: 1. Clicks `Add provider` of type `OpenID Connect`. @@ -95,19 +113,19 @@ The flow from the user's point of view should be the following: 1. The user is asked to create or assign an existing role. 2. The role's `Policies` must be filled with the required Policies (described down below). 3. The role's `Trust relationships` must target the Identity Provider they just created (described down below). -6. The user will be greeted with a message saying that the configuration was successful. +6. The user will be greeted with a message in Teleport saying that the configuration was successful. To ease the necessary manual steps, the Discover wizard will provide a small video demoing what the user must do for the previous steps. -#### System's Point of View -As for the flow that happens automatically, we have the following: +At this point, the integration is configured and the user is able to discover RDS DBs without leaving Teleport. +#### System's Point of View The first interaction between AWS and Teleport happens when the user clicks on `Get Thumbprint` (step 4 of the User's Point of View flow). -This will trigger a request started by AWS to Teleport hitting the OpenID Configuration endpoint and subsequently the JSON Web Key Set endpoint (3). +This will trigger a request started by AWS to Teleport hitting the OpenID Configuration endpoint and subsequently the JSON Web Key Set endpoint. -After this step, when the user tries to list a resource (eg, RDS databases), Teleport generates a token and issues the API call. +After this step, when the user tries to list RDS DBs, Teleport generates a token and issues the API call. -To generate a token, Teleport creates a JWT with the claims described above and sign it with the private key (the public is provided in the public JWKS endpoint). +To generate a token, Teleport creates a JWT with the claims described above and the configured role, and signs it with the private key (the public is provided in the public JWKS endpoint). AWS receives the request and validates the token against the public key provided by OIDC IdP (ie, Teleport) at the `jwks_uri`. If authenticated and authorized for the api call, AWS returns the response to the API call. @@ -117,10 +135,13 @@ If authenticated and authorized for the api call, AWS returns the response to th #### Signing Key One of the requirements to be an OIDC provider is to provide the public key in a known HTTP endpoint and sign a JSON object (with claims) with the private key. -We'll re-use the RSA key that exists to sign JWT tokens for App Access. +We'll create a new RSA 2048 Key type and add it to the CertAuthority. +This will be very similar to the JWTSigner key type used for App access. + +A single signing key will be used for this flow even if multiple AWS integrations are created (eg, multiple regions). #### HTTP Endpoints -We'll use two HTTP endpoints: +The following endpoints will be used during OIDC IdP set up: ##### OpenID Configuration According to the [spec](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig) the Identity Provider must provide an endpoint at `/.well-known/openid-configuration` that returns the provider's configuration. @@ -131,7 +152,7 @@ So, a new endpoint at `/.well-known/openid-configuration` w { "issuer": "", - "jwks_uri": "/.well-known/jwks.json", + "jwks_uri": "/.well-known/jwks-oidc", "claims": ["iss", "sub", "aud", "jti", "iat", "exp", "nbf"], "id_token_signing_alg_values_supported": ["RS256"], "response_types_supported": ["id_token"], @@ -161,7 +182,7 @@ This endpoint returns a list of public keys (usually only one key, except for pe This endpoint URI must be equal to `jwks_uri` defined in the previous section. -As an example, `/.well-known/jwks.json`. +As an example, `/.well-known/jwks-oidc`. It should return the following: @@ -182,12 +203,22 @@ It should return the following: This must respect the RFC7517 (eg of a key can be found at https://www.rfc-editor.org/rfc/rfc7517#appendix-A.1). -We'll re-use the current endpoint located at `https:///.well-known/jwks.json`. +Obtaining this key should be possible using +```golang +GetCertAuthority( + ctx, + types.CertAuthID{ + Type: types.OIDCSigner, // new key type + DomainName: clusterName, + }, + false /*loadKeys*/, +) +``` #### AWS Role for Teleport OIDC IdP -The user will create or associate a role to the Teleport OIDC IdP. -This role must have access to list RDS Databases and have that Identity Provider as a trusted policy. +The user will create or associate an AWS Role to the Teleport OIDC IdP. +This role must have access to list RDS Databases and have a policy that trusts Teleport as an Identity Provider. At least a policy allowing the following must be part of the role: ```json @@ -203,7 +234,8 @@ At least a policy allowing the following must be part of the role: } ``` -Trusted relationship: +The AWS Role must trust Teleport as an IdP. +To do so, the user must add the following Trusted relationship: ```json { "Version": "2012-10-17", @@ -227,7 +259,7 @@ Trusted relationship: ### Security #### Rotation -JWT Signging keys can be rotated using `tctl auth rotate --type=jwt`. +JWT Signing keys can be rotated using `tctl auth rotate --type=oidc`. JWKS endpoint returns a list of public keys, so the old and the new key are provided for a seamless migration. @@ -244,10 +276,10 @@ We don't think this is a scenario we should focus on this RFD. We'll be able to call `DescribeDBInstances` AWS endpoint, however we must ensure that this is protected by RBAC. In order to do so, we'll re-use the `db` resource with the `list` verb to allow listing RDS Databases. + ```yaml kind: role metadata: - description: Edit cluster configuration name: editor spec: allow: From c5a4fe9dc76f2faff2cc9c0b16fa1c1e671e6c38 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Wed, 8 Mar 2023 16:59:10 +0000 Subject: [PATCH 03/14] review pt1 --- ...=> 9999-aws-api-integration-using-oidc.md} | 133 +++++++++++++----- 1 file changed, 96 insertions(+), 37 deletions(-) rename rfd/{9999-oidc-idp-for-aws-rds-dbs-discovery.md => 9999-aws-api-integration-using-oidc.md} (84%) diff --git a/rfd/9999-oidc-idp-for-aws-rds-dbs-discovery.md b/rfd/9999-aws-api-integration-using-oidc.md similarity index 84% rename from rfd/9999-oidc-idp-for-aws-rds-dbs-discovery.md rename to rfd/9999-aws-api-integration-using-oidc.md index 5ea069decd63b..c69fde0a84d56 100644 --- a/rfd/9999-oidc-idp-for-aws-rds-dbs-discovery.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -3,7 +3,7 @@ authors: Marco Dinis (marco.dinis@goteleport.com) state: draft --- -# RFD 999 - OIDC IdP for AWS RDS DBs discovery +# RFD 999 - AWS API Integration using OIDC ## Required Approvals @@ -13,20 +13,20 @@ state: draft ## What -Discover AWS RDS Databases without manual configuration. +Integrate with AWS using an OIDC IdP. #### Goals -Easily discover AWS RDS Databases of an account. +Ease the AWS resource discovery and onboarding. + +This feature must work for OSS, Enterprise and Cloud customers. #### Non-goals -Having a real OIDC IdP is out of scope. +Having a real OIDC IdP. That initiative can be tracked [here](https://github.com/gravitational/teleport/issues/20967). -Automatically onboard AWS RDS Databases into Teleport. - -Discovering other AWS resources is out of scope. +Automatically onboard AWS resources into Teleport. ## Terminology @@ -38,10 +38,18 @@ Discovering other AWS resources is out of scope. ## Why Our current discovery process for AWS resources requires multiple steps before the user gets to the "aha moment". -Some of those steps are a little complicated and require the user to know some Teleport specific internals. -We can reduce the number of steps and remove most of the Teleport specific configuration by creating an OIDC IdP in Teleport. +For example, to set up an RDS DB the user must do the following: +- enter database name +- enter Database endpoint, port, resource id and AWS Account ID +- start a Database Agent by running a shell script (`database-install.sh`) in a EC2 instance +- create an IAM Policy +- add Database User and Database Name to the current user's traits +- user can connect to this Database + +Configuring the IAM Policy, installing the Database Agent or setting up the traits the is sometimes challenging and we lose users before they get the "aha moment". +Using AWS OIDC Integration allows Teleport services to call AWS API methods to obtain most of this information instead of asking the user. ## How AWS allows the [set up](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) of an IdP using OIDC providers. @@ -54,16 +62,6 @@ When configuring the provider, we'll need an AWS Role which Teleport uses to iss To store the configuration above, we'll create a new resource Kind: `Integration`. It'll leverage the `subkind` prop to distinguish future integrations. -```yaml -kind: integration -subkind: aws-oidc -version: v1 -metadata: - name: some-name -spec: - aws_role: -``` - ### High Level Flow Simplified flow of interactions between User, Teleport and AWS: @@ -86,7 +84,7 @@ User────────────┤ │ │ │ │ │ │ │ ┌─────────▼┐ │ │ │ │ │ CA KeySet│ │ │ - │ │ │ +RSA Key │ │ │ + │ │ │ +OIDC CA │ │ │ │ │ └─────────▲┘ │ │ │ │6 │7 │ │ │ │ ┌──────┴────┐ │ │ @@ -135,8 +133,8 @@ If authenticated and authorized for the api call, AWS returns the response to th #### Signing Key One of the requirements to be an OIDC provider is to provide the public key in a known HTTP endpoint and sign a JSON object (with claims) with the private key. -We'll create a new RSA 2048 Key type and add it to the CertAuthority. -This will be very similar to the JWTSigner key type used for App access. +We'll create a new CA: OIDCCA. +This will be similar to the JWTSigner key type used for App access. A single signing key will be used for this flow even if multiple AWS integrations are created (eg, multiple regions). @@ -146,13 +144,13 @@ The following endpoints will be used during OIDC IdP set up: ##### OpenID Configuration According to the [spec](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig) the Identity Provider must provide an endpoint at `/.well-known/openid-configuration` that returns the provider's configuration. -So, a new endpoint at `/.well-known/openid-configuration` will be created that returns the following JSON: +So, a new endpoint at `/.well-known/openid-configuration` will be created that returns the following JSON: ``` 200 OK { - "issuer": "", - "jwks_uri": "/.well-known/jwks-oidc", + "issuer": "https://proxy.example.com", + "jwks_uri": "https://proxy.example.com/.well-known/jwks-oidc", "claims": ["iss", "sub", "aud", "jti", "iat", "exp", "nbf"], "id_token_signing_alg_values_supported": ["RS256"], "response_types_supported": ["id_token"], @@ -161,13 +159,13 @@ So, a new endpoint at `/.well-known/openid-configuration` w } ``` -- Issuer: the provider's URL +- Issuer: the proxy's public address - JWKS URI: the endpoint where the provider returns the public keys. - Claims Supported: a list of supported claims that the OpenID Provider (ie, Teleport) MAY be able to supply values for when issuing a token: - `iss`: the issuer identity, on our case it will be the same as the `issuer` key. - - `sub`: identifies the subject of the token, on our case it will contain the user's name. + - `sub`: identifies the subject of the token, in our case it will contain the Teleport username prefixed by `user:` - `aud`: the audience for the token, on our case it will be the same as the `audience` defined when configuring the OIDC IdP in AWS (step 3.3 for the User's Point of View). - - `jti`: is the token id. + - `jti`: is the token id (UUIDv4). - `iat`: unix epoch time of when the token was issued. - `exp`: unix epoch time of when the token is no longer valid (expired). - `nbf`: unix epoch time which indicates when the token began to be valid. @@ -182,7 +180,7 @@ This endpoint returns a list of public keys (usually only one key, except for pe This endpoint URI must be equal to `jwks_uri` defined in the previous section. -As an example, `/.well-known/jwks-oidc`. +As an example, `https://proxy.example.com/.well-known/jwks-oidc`. It should return the following: @@ -218,23 +216,25 @@ GetCertAuthority( #### AWS Role for Teleport OIDC IdP The user will create or associate an AWS Role to the Teleport OIDC IdP. -This role must have access to list RDS Databases and have a policy that trusts Teleport as an Identity Provider. -At least a policy allowing the following must be part of the role: +As an example, we the following is the required policy to list RDS DBs (including Aurora clusters): ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", - "Action": "rds:DescribeDBInstances", + "Actions": "[ + rds:DescribeDBClusters", + rds:DescribeDBInstances", + ], "Resource": "*" } ] } ``` -The AWS Role must trust Teleport as an IdP. +This AWS Role must trust Teleport as an IdP. To do so, the user must add the following Trusted relationship: ```json { @@ -243,12 +243,12 @@ To do so, the user must add the following Trusted relationship: { "Effect": "Allow", "Principal": { - "Federated": "arn:aws:iam:::oidc-provider/" + "Federated": "arn:aws:iam::0123456789012:oidc-provider/proxy.example.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { - ":aud": "sts.amazonaws.com" + "proxy.example.com:aud": "sts.amazonaws.com" } } } @@ -256,6 +256,65 @@ To do so, the user must add the following Trusted relationship: } ``` +### UX +Besides the flow describe above (Users Point Of View), the Integration resource will have the usual CRUD operations via both API and `tctl`. +The only updatable field is `aws_role_arn`. + +HTTP API: +``` +Methods: +GET .../integration +GET .../integration/:id +POST .../integration +PUT .../integration/:id +DELETE .../integration/:id +``` +JSON representation: +```json +{ + "name": "myaws", + "subkind": "aws-oidc" + "subkindData": { + "aws_role_arn": "arn:aws:123:TeleportOIDC" + } +} +``` + +`tctl`: + +``` +$ tctl get integrations +kind: integration +subkind: aws-oidc +version: v1 +metadata: + name: some-name +spec: + aws_role_arn: arn:aws:123:TeleportOIDC + +$ tctl get integration/myaws +kind: integration +subkind: aws-oidc +version: v1 +metadata: + name: some-name +spec: + aws_role_arn: arn:aws:123:TeleportOIDC + +$ tctl create aws-integration.yaml +``` + +Resource representation as `yaml`: +```yaml +kind: integration +subkind: aws-oidc +version: v1 +metadata: + name: myaws +spec: + aws_role_arn: arn:aws:123:TeleportOIDC +``` + ### Security #### Rotation @@ -266,9 +325,9 @@ JWKS endpoint returns a list of public keys, so the old and the new key are prov #### MITM between AWS and Teleport The only configuration AWS has about the provider is its URL. -If that DNS is controlled by some evil part, AWS might accept requests from that evil part. +If DNS is controlled by an attacker, AWS might accept requests from them. -However, assuming the DNS is controlled by an evil part, then the users that are logging in to Teleport are also providing their credentials to that part. +However, assuming the DNS is controlled by an attacker, then the users that are logging in to Teleport are also providing their credentials to that part. We don't think this is a scenario we should focus on this RFD. From 75ed58476371b4c8eb513258ead3829959ee647b Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Mon, 20 Mar 2023 14:59:07 +0000 Subject: [PATCH 04/14] review --- rfd/9999-aws-api-integration-using-oidc.md | 39 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index c69fde0a84d56..5404be50d531a 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -62,6 +62,8 @@ When configuring the provider, we'll need an AWS Role which Teleport uses to iss To store the configuration above, we'll create a new resource Kind: `Integration`. It'll leverage the `subkind` prop to distinguish future integrations. +Multiple AWS Integrations might exist in the same cluster. + ### High Level Flow Simplified flow of interactions between User, Teleport and AWS: @@ -97,8 +99,8 @@ User────────────┤ ``` #### User's Point of View -When the user adds a new resource, using the Discover Wizard, they'll be asked where the resource lives. -Choosing an RDS DB, the user is presented with the following flow: +When a user adds a new AWS Integration, they will go through the following. +Users will also be asked to set up an AWS integration when adding RDS databases in Discover flow. 1. User is prompted to setup an OIDC Identity Provider pointing to its Teleport instance's url. 2. User opens AWS, selects IAM and then, under `Access Management`, selects `Identity providers`. @@ -117,13 +119,16 @@ To ease the necessary manual steps, the Discover wizard will provide a small vid At this point, the integration is configured and the user is able to discover RDS DBs without leaving Teleport. +To do so, when trying to add a RDS Database, they will be asked to select which AWS Integration to use. +If there's only one AWS Integration, that it will be selected without user's interaction to reduce the required steps. + #### System's Point of View The first interaction between AWS and Teleport happens when the user clicks on `Get Thumbprint` (step 4 of the User's Point of View flow). This will trigger a request started by AWS to Teleport hitting the OpenID Configuration endpoint and subsequently the JSON Web Key Set endpoint. After this step, when the user tries to list RDS DBs, Teleport generates a token and issues the API call. -To generate a token, Teleport creates a JWT with the claims described above and the configured role, and signs it with the private key (the public is provided in the public JWKS endpoint). +To generate a token, Teleport creates a JWT with the claims described [below](#openid-configuration) and the configured role, and signs it with the private key (the public is provided in the public JWKS endpoint). AWS receives the request and validates the token against the public key provided by OIDC IdP (ie, Teleport) at the `jwks_uri`. If authenticated and authorized for the api call, AWS returns the response to the API call. @@ -134,7 +139,8 @@ If authenticated and authorized for the api call, AWS returns the response to th One of the requirements to be an OIDC provider is to provide the public key in a known HTTP endpoint and sign a JSON object (with claims) with the private key. We'll create a new CA: OIDCCA. -This will be similar to the JWTSigner key type used for App access. +This will be similar to the SAML IdP CA. +It'll use RS256. A single signing key will be used for this flow even if multiple AWS integrations are created (eg, multiple regions). @@ -151,7 +157,7 @@ So, a new endpoint at `/.well-known/openid-configuration` will { "issuer": "https://proxy.example.com", "jwks_uri": "https://proxy.example.com/.well-known/jwks-oidc", - "claims": ["iss", "sub", "aud", "jti", "iat", "exp", "nbf"], + "claims": ["iss", "sub", "obo", "aud", "jti", "iat", "exp", "nbf"], "id_token_signing_alg_values_supported": ["RS256"], "response_types_supported": ["id_token"], "scopes_supported": ["openid"], @@ -163,7 +169,8 @@ So, a new endpoint at `/.well-known/openid-configuration` will - JWKS URI: the endpoint where the provider returns the public keys. - Claims Supported: a list of supported claims that the OpenID Provider (ie, Teleport) MAY be able to supply values for when issuing a token: - `iss`: the issuer identity, on our case it will be the same as the `issuer` key. - - `sub`: identifies the subject of the token, in our case it will contain the Teleport username prefixed by `user:` + - `sub`: identifies the subject of the token, in our case it will contain the Teleport proxy system `system:proxy` + - `obo`: identifies the Teleport username that requested the token prefixed by `user:` - `aud`: the audience for the token, on our case it will be the same as the `audience` defined when configuring the OIDC IdP in AWS (step 3.3 for the User's Point of View). - `jti`: is the token id (UUIDv4). - `iat`: unix epoch time of when the token was issued. @@ -257,7 +264,12 @@ To do so, the user must add the following Trusted relationship: ``` ### UX -Besides the flow describe above (Users Point Of View), the Integration resource will have the usual CRUD operations via both API and `tctl`. + +#### Web flow +Described [above](#user_s-point-of-view). + +#### Web API +Integration resource will have the usual CRUD operations via Web API. The only updatable field is `aws_role_arn`. HTTP API: @@ -279,6 +291,10 @@ JSON representation: } } ``` +#### CLI +Users can also create/update the resource using `tctl`. + +The only updatable field is `aws_role_arn`. `tctl`: @@ -315,6 +331,15 @@ spec: aws_role_arn: arn:aws:123:TeleportOIDC ``` +#### IaC - Terraform +A new resource `Integration` must be created to allow for the Integration management from the Terraform provider. + +#### IaC - Kube Operator +A new resource `Integration` must be created to allow for the Integration management from the Kube Operator. + +#### IaC - Helm Charts +No change will be made to the Helm Charts because there's no new configuration changes. + ### Security #### Rotation From 0ad5ad9bee7caca498eafe581fca02ffb1c58150 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Mon, 20 Mar 2023 16:05:50 +0000 Subject: [PATCH 05/14] integration action --- rfd/9999-aws-api-integration-using-oidc.md | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index 5404be50d531a..7ae48b52cb2fa 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -291,6 +291,45 @@ JSON representation: } } ``` + +In order to call an Integration action, we'll create a new Web API endpoint: +``` +---> +POST .../integration/:id/action/aws-oidc-list-databases +{} + +<--- +{ + "status": "success", + "response": { + "items": [ + { + "status": "available", + "name": "marcodbtest", + "iamAuth": "true", + "engine": "postgres", + "engineVersion": "15.2", + "masterUsername": "postgres", + "tags": [], + "arn": "arn:aws:rds:us-east-1::db:marcodbtest", + "addr": "marcodbtest..us-east-1.rds.amazonaws.com", + "port": "5432" + } + ] + } +} +``` + +This will generate a new token for the Integration `:id` and then call the `aws-oidc-list-databases` method which maps to a method that will do two AWS API Calls: +- `rds describe-db-instances` +- `rds describe-db-clusters` + +The response contains the following fields: +- `status`: reports the result of calling the integration (other errors will come as usual: http status code) +- `response`: specific to the requested action + +Pagination/Offset and search capabilities are out of scope for now. + #### CLI Users can also create/update the resource using `tctl`. From 36076d7dd5f305b20af54d329242d36a5b4dd6d1 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Mon, 20 Mar 2023 16:49:35 +0000 Subject: [PATCH 06/14] updated rbac rules to use the integration --- rfd/9999-aws-api-integration-using-oidc.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index 7ae48b52cb2fa..329b7ebf32f5a 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -396,9 +396,12 @@ However, assuming the DNS is controlled by an attacker, then the users that are We don't think this is a scenario we should focus on this RFD. #### AWS Calls from unauthorized Teleport Users -We'll be able to call `DescribeDBInstances` AWS endpoint, however we must ensure that this is protected by RBAC. +We'll be able to call `DescribeDBInstances/Clusters` AWS endpoint, however we must ensure that this is protected by RBAC. -In order to do so, we'll re-use the `db` resource with the `list` verb to allow listing RDS Databases. +In order to do so, we'll add a new verb: `use`. +This verb defines whether the user can use an integration's action. + +The user needs the following rules in order to call an external integration endpoint: ```yaml kind: role @@ -408,9 +411,9 @@ spec: allow: rules: - resources: - - db + - integration verbs: - - list + - use ``` ## Proof of Concept From 9ca517ff356c23ae5ba2327169224b6977f81041 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Mon, 20 Mar 2023 16:51:40 +0000 Subject: [PATCH 07/14] fix aws policy actions list --- rfd/9999-aws-api-integration-using-oidc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index 329b7ebf32f5a..edd7efff5e915 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -231,9 +231,9 @@ As an example, we the following is the required policy to list RDS DBs (includin "Statement": [ { "Effect": "Allow", - "Actions": "[ - rds:DescribeDBClusters", - rds:DescribeDBInstances", + "Actions": [ + "rds:DescribeDBClusters", + "rds:DescribeDBInstances" ], "Resource": "*" } From b8f7491288fe83254589b84bd1f814387ac39d37 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Wed, 22 Mar 2023 17:28:13 +0000 Subject: [PATCH 08/14] update aud claim to discover.teleport --- rfd/9999-aws-api-integration-using-oidc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index edd7efff5e915..b838bb0046fa0 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -107,7 +107,7 @@ Users will also be asked to set up an AWS integration when adding RDS databases 3. Configures the Teleport instance as an OIDC IdP: 1. Clicks `Add provider` of type `OpenID Connect`. 2. Fills in the Provider URL as provided by the Discover Wizard. - 3. Fills in the Audience as provided by the Discover Wizard `sts.amazonaws.com`. + 3. Fills in the Audience as provided by the Discover Wizard `discover.teleport`. 4. The user is then asked to enter the Thumbprint in Teleport, to ensure the user entered the correct `Provider URL`. 5. Configures the role associated with that IdP 1. The user is asked to create or assign an existing role. @@ -255,7 +255,7 @@ To do so, the user must add the following Trusted relationship: "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { - "proxy.example.com:aud": "sts.amazonaws.com" + "proxy.example.com:aud": "discover.teleport" } } } @@ -549,7 +549,7 @@ func main() { Issuer: "https://" + URL, Subject: "some-subject", ID: "id1", - Audience: jwt.Audience{"sts.amazonaws.com"}, + Audience: jwt.Audience{"discover.teleport"}, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), } From 4c1c1bdac6753fee8ae28bc867100784b47253a0 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Thu, 23 Mar 2023 18:32:04 +0000 Subject: [PATCH 09/14] add sec notes about thumbprint --- rfd/9999-aws-api-integration-using-oidc.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index b838bb0046fa0..4ef8829df9297 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -1,4 +1,4 @@ ---- +****--- authors: Marco Dinis (marco.dinis@goteleport.com) state: draft --- @@ -64,6 +64,10 @@ It'll leverage the `subkind` prop to distinguish future integrations. Multiple AWS Integrations might exist in the same cluster. +For security reasons, AWS stores a thumbprint associated with the CA that issue the HTTPS cert for Teleport. +If Teleport moves to another CA, then AWS will no longer accept calls from Teleport and a new set up is required. +More information about this in the Security section. + ### High Level Flow Simplified flow of interactions between User, Teleport and AWS: @@ -388,12 +392,13 @@ JWKS endpoint returns a list of public keys, so the old and the new key are prov #### MITM between AWS and Teleport -The only configuration AWS has about the provider is its URL. -If DNS is controlled by an attacker, AWS might accept requests from them. +During the initial set up, AWS records a [thumbprint](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html) for the provider. + +This thumbprint is the hex-encoded SHA-1 hash value of the top intermediate CA that signed the certificate used by Teleport to make its keys available (this is the `jwks_uri`'s domain). -However, assuming the DNS is controlled by an attacker, then the users that are logging in to Teleport are also providing their credentials to that part. +If an attacker is able to control AWS's DNS resolvers and obtain a valid certificate from the top intermediate CA that signed the certificate, then they might be able to impersonate Teleport and AWS might accept requests from the attacker. -We don't think this is a scenario we should focus on this RFD. +However, assuming the AWS's DNS resolvers are controlled by an attacker is a scenario we should not focus on this RFD. #### AWS Calls from unauthorized Teleport Users We'll be able to call `DescribeDBInstances/Clusters` AWS endpoint, however we must ensure that this is protected by RBAC. From dc6fc61a29c834091452746a74b190350a9b6d16 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Fri, 24 Mar 2023 09:16:11 +0000 Subject: [PATCH 10/14] add cluster alert for outdate thumbprint --- rfd/9999-aws-api-integration-using-oidc.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index 4ef8829df9297..c3fcb595b7033 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -1,4 +1,4 @@ -****--- +--- authors: Marco Dinis (marco.dinis@goteleport.com) state: draft --- @@ -64,8 +64,10 @@ It'll leverage the `subkind` prop to distinguish future integrations. Multiple AWS Integrations might exist in the same cluster. -For security reasons, AWS stores a thumbprint associated with the CA that issue the HTTPS cert for Teleport. -If Teleport moves to another CA, then AWS will no longer accept calls from Teleport and a new set up is required. +For security reasons, AWS stores a thumbprint associated with the CA that issued the HTTPS cert for Teleport. +If Teleport moves to another CA, then AWS will no longer accept calls from Teleport. +When that happens, a Cluster Alert is created informing the user about it and asking them to reset the thumbprint in AWS. + More information about this in the Security section. ### High Level Flow From e0fe667bbf3eafee53a35e14d5e8bb5716af9157 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Fri, 31 Mar 2023 18:18:37 +0100 Subject: [PATCH 11/14] add integration status --- rfd/9999-aws-api-integration-using-oidc.md | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index c3fcb595b7033..f558f7c868832 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -276,7 +276,12 @@ Described [above](#user_s-point-of-view). #### Web API Integration resource will have the usual CRUD operations via Web API. -The only updatable field is `aws_role_arn`. + +The user can only update two fields: +- awsOIDC.roleARN: to set the AWS Role that should be used for this Integration +- status: + - Paused: when the Integration should not be used, to support a disable operation + - Running: when the Integration is running HTTP API: ``` @@ -291,10 +296,11 @@ JSON representation: ```json { "name": "myaws", - "subkind": "aws-oidc" - "subkindData": { - "aws_role_arn": "arn:aws:123:TeleportOIDC" - } + "subkind": "aws-oidc", + "awsOIDC": { + "roleARN": "arn:aws:123:TeleportOIDC" + }, + "status": "IntegrationStatusRunning" } ``` @@ -339,7 +345,7 @@ Pagination/Offset and search capabilities are out of scope for now. #### CLI Users can also create/update the resource using `tctl`. -The only updatable field is `aws_role_arn`. +The only updatable field is `role_arn`. `tctl`: @@ -351,7 +357,9 @@ version: v1 metadata: name: some-name spec: - aws_role_arn: arn:aws:123:TeleportOIDC + subkind_spec: + aws_oidc: + role_arn: arn:aws:123:TeleportOIDC $ tctl get integration/myaws kind: integration @@ -360,7 +368,9 @@ version: v1 metadata: name: some-name spec: - aws_role_arn: arn:aws:123:TeleportOIDC + subkind_spec: + aws_oidc: + role_arn: arn:aws:123:TeleportOIDC $ tctl create aws-integration.yaml ``` @@ -373,7 +383,9 @@ version: v1 metadata: name: myaws spec: - aws_role_arn: arn:aws:123:TeleportOIDC + subkind_spec: + aws_oidc: + role_arn: arn:aws:123:TeleportOIDC ``` #### IaC - Terraform From 2903f9be5a3c5104c72aaa2c30a4d2ab75cfd846 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Tue, 4 Apr 2023 09:00:17 +0100 Subject: [PATCH 12/14] add proto representation of integration --- rfd/9999-aws-api-integration-using-oidc.md | 420 ++++++++++++--------- 1 file changed, 233 insertions(+), 187 deletions(-) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/9999-aws-api-integration-using-oidc.md index f558f7c868832..cd0c0742e6ca4 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/9999-aws-api-integration-using-oidc.md @@ -62,6 +62,51 @@ When configuring the provider, we'll need an AWS Role which Teleport uses to iss To store the configuration above, we'll create a new resource Kind: `Integration`. It'll leverage the `subkind` prop to distinguish future integrations. +```proto +// IntegrationV1 represents a connection between Teleport and some other 3rd party system. +// This connection allows API access to that service from Teleport. +// Each Integration instance must have a SubKind defined which identifies the external system. +message IntegrationV1 { + // Header is the resource header. + ResourceHeader Header = 1; + + // Spec is an Integration specification. + IntegrationSpecV1 Spec = 2 ; +} + +// IntegrationSpecV1 contains properties of all the supported integrations. +message IntegrationSpecV1 { + oneof SubKindSpec { + // AWSOIDC contains the specific fields to handle the AWS OIDC Integration subkind + AWSOIDCIntegrationSpecV1 AWSOIDC = 1; + } + + // IntegrationStatus contains the current integration status. + enum IntegrationStatus { + INTEGRATION_STATUS_UNSPECIFIED = 0; + + // Integration is not running because it was just created or was disabled by the user. + INTEGRATION_STATUS_PAUSED = 1; + + // Integration is running. + INTEGRATION_STATUS_RUNNING = 2; + + // Integration has an error and that should be fixed before receiving requests. + INTEGRATION_STATUS_ERROR = 3; + } + + // Status contains the current Integration Status + IntegrationStatus status = 2; +} + +// AWSOIDCIntegrationSpecV1 contains the spec properties for the AWS OIDC SubKind Integration. +message AWSOIDCIntegrationSpecV1 { + // RoleARN contains the Role ARN used to set up the Integration. + // This is the AWS Role that Teleport will use to issue tokens for API Calls. + string RoleARN = 1; +} +``` + Multiple AWS Integrations might exist in the same cluster. For security reasons, AWS stores a thumbprint associated with the CA that issued the HTTPS cert for Teleport. @@ -217,12 +262,12 @@ This must respect the RFC7517 (eg of a key can be found at https://www.rfc-edito Obtaining this key should be possible using ```golang GetCertAuthority( - ctx, - types.CertAuthID{ - Type: types.OIDCSigner, // new key type - DomainName: clusterName, - }, - false /*loadKeys*/, + ctx, + types.CertAuthID{ + Type: types.OIDCSigner, // new key type + DomainName: clusterName, + }, + false /*loadKeys*/, ) ``` @@ -238,9 +283,9 @@ As an example, we the following is the required policy to list RDS DBs (includin { "Effect": "Allow", "Actions": [ - "rds:DescribeDBClusters", - "rds:DescribeDBInstances" - ], + "rds:DescribeDBClusters", + "rds:DescribeDBInstances" + ], "Resource": "*" } ] @@ -280,8 +325,8 @@ Integration resource will have the usual CRUD operations via Web API. The user can only update two fields: - awsOIDC.roleARN: to set the AWS Role that should be used for this Integration - status: - - Paused: when the Integration should not be used, to support a disable operation - - Running: when the Integration is running + - Paused: when the Integration should not be used, to support a disable operation + - Running: when the Integration is running HTTP API: ``` @@ -295,12 +340,12 @@ DELETE .../integration/:id JSON representation: ```json { - "name": "myaws", - "subkind": "aws-oidc", - "awsOIDC": { - "roleARN": "arn:aws:123:TeleportOIDC" - }, - "status": "IntegrationStatusRunning" + "name": "myaws", + "subkind": "aws-oidc", + "awsOIDC": { + "roleARN": "arn:aws:123:TeleportOIDC" + }, + "status": "IntegrationStatusRunning" } ``` @@ -355,22 +400,23 @@ kind: integration subkind: aws-oidc version: v1 metadata: - name: some-name + name: some-name spec: - subkind_spec: - aws_oidc: - role_arn: arn:aws:123:TeleportOIDC + subkind_spec: + aws_oidc: + role_arn: arn:aws:123:TeleportOIDC $ tctl get integration/myaws kind: integration subkind: aws-oidc version: v1 metadata: - name: some-name + name: some-name spec: - subkind_spec: - aws_oidc: - role_arn: arn:aws:123:TeleportOIDC + subkind_spec: + aws_oidc: + role_arn: arn:aws:123:TeleportOIDC + status: INTEGRATION_STATUS_RUNNING $ tctl create aws-integration.yaml ``` @@ -381,11 +427,11 @@ kind: integration subkind: aws-oidc version: v1 metadata: - name: myaws + name: myaws spec: - subkind_spec: - aws_oidc: - role_arn: arn:aws:123:TeleportOIDC + subkind_spec: + aws_oidc: + role_arn: arn:aws:123:TeleportOIDC ``` #### IaC - Terraform @@ -446,50 +492,50 @@ Check the `TODO`s within the source code. package main import ( - "crypto/rsa" - "crypto/x509" - _ "embed" - "encoding/pem" - "fmt" - "net/http" - "os" - "time" - - "github.com/aws/aws-sdk-go-v2/config" - "github.com/aws/aws-sdk-go-v2/credentials/stscreds" - "github.com/aws/aws-sdk-go-v2/service/rds" - "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/aws/aws-sdk-go-v2/service/sts" - "github.com/go-jose/go-jose/v3" - "github.com/go-jose/go-jose/v3/jwt" - "github.com/gravitational/trace" - "github.com/labstack/echo/v4" - "github.com/labstack/echo/v4/middleware" - "github.com/olekukonko/tablewriter" + "crypto/rsa" + "crypto/x509" + _ "embed" + "encoding/pem" + "fmt" + "net/http" + "os" + "time" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/rds" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/go-jose/go-jose/v3" + "github.com/go-jose/go-jose/v3/jwt" + "github.com/gravitational/trace" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "github.com/olekukonko/tablewriter" ) type DiscoveryConfiguration struct { - // Issuer is the identifier of the OP and is used in the tokens as `iss` claim. - Issuer string `json:"issuer,omitempty"` + // Issuer is the identifier of the OP and is used in the tokens as `iss` claim. + Issuer string `json:"issuer,omitempty"` - // JwksURI is the URL of the JSON Web Key Set. This site contains the signing keys that RPs can use to validate the signature. - // It may also contain the OP's encryption keys that RPs can use to encrypt request to the OP. - JwksURI string `json:"jwks_uri,omitempty"` + // JwksURI is the URL of the JSON Web Key Set. This site contains the signing keys that RPs can use to validate the signature. + // It may also contain the OP's encryption keys that RPs can use to encrypt request to the OP. + JwksURI string `json:"jwks_uri,omitempty"` - // ClaimsSupported contains a list of Claim Names the OP may be able to supply values for. This list might not be exhaustive. - ClaimsSupported []string `json:"claims_supported,omitempty"` + // ClaimsSupported contains a list of Claim Names the OP may be able to supply values for. This list might not be exhaustive. + ClaimsSupported []string `json:"claims_supported,omitempty"` - // IDTokenSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for the ID Token. - IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"` + // IDTokenSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for the ID Token. + IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"` - // ResponseTypesSupported contains a list of the OAuth 2.0 response_type values that the OP supports (code, id_token, token id_token, ...). - ResponseTypesSupported []string `json:"response_types_supported,omitempty"` + // ResponseTypesSupported contains a list of the OAuth 2.0 response_type values that the OP supports (code, id_token, token id_token, ...). + ResponseTypesSupported []string `json:"response_types_supported,omitempty"` - // ScopesSupported lists an array of supported scopes. This list must not include every supported scope by the OP. - ScopesSupported []string `json:"scopes_supported,omitempty"` + // ScopesSupported lists an array of supported scopes. This list must not include every supported scope by the OP. + ScopesSupported []string `json:"scopes_supported,omitempty"` - // SubjectTypesSupported contains a list of Subject Identifier types that the OP supports (pairwise, public). - SubjectTypesSupported []string `json:"subject_types_supported,omitempty"` + // SubjectTypesSupported contains a list of Subject Identifier types that the OP supports (pairwise, public). + SubjectTypesSupported []string `json:"subject_types_supported,omitempty"` } // $ openssl genrsa -out keypair.pem 2048 @@ -506,135 +552,135 @@ type IdentityToken string // GetIdentityToken retrieves the JWT token from the file and returns the contents as a []byte func (j IdentityToken) GetIdentityToken() ([]byte, error) { - return []byte(j), nil + return []byte(j), nil } func main() { - e := echo.New() - e.Debug = true - e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ - Format: "method=${method}, uri=${uri}, status=${status}\n", - })) - - block, _ := pem.Decode([]byte(privateKey)) - parseResult, _ := x509.ParsePKCS8PrivateKey(block.Bytes) - key := parseResult.(*rsa.PrivateKey) - - e.GET("/v1/.well-known/openid-configuration", func(c echo.Context) error { - discovery := &DiscoveryConfiguration{ - Issuer: "https://" + URL, - JwksURI: "https://" + URL + "/.well-known/jwks", - ClaimsSupported: []string{"sub", "aud", "exp", "iat", "iss", "jti", "nbf", "ref"}, - IDTokenSigningAlgValuesSupported: []string{"RS256"}, - ResponseTypesSupported: []string{"id_token"}, - ScopesSupported: []string{"openid"}, - SubjectTypesSupported: []string{"public", "pairwise"}, - } - - return c.JSON(http.StatusOK, discovery) - }) - - e.GET("/v1/.well-known/jwks", func(c echo.Context) error { - keyset := &jose.JSONWebKeySet{ - Keys: []jose.JSONWebKey{ - { - KeyID: "id", - Algorithm: "RS256", - Use: "sig", - Key: &key.PublicKey, - }, - }, - } - - return c.JSON(http.StatusOK, keyset) - }) - - e.GET("/aws", func(c echo.Context) error { - ctx := c.Request().Context() - - key := jose.SigningKey{Algorithm: jose.RS256, Key: key} - - // create a Square.jose RSA signer, used to sign the JWT - var signerOpts = jose.SignerOptions{} - signerOpts.WithType("JWT") - rsaSigner, err := jose.NewSigner(key, &signerOpts) - if err != nil { - return trace.Wrap(err) - } - - builder := jwt.Signed(rsaSigner) - - pubClaims := jwt.Claims{ - Issuer: "https://" + URL, - Subject: "some-subject", - ID: "id1", - Audience: jwt.Audience{"discover.teleport"}, - IssuedAt: jwt.NewNumericDate(time.Now()), - Expiry: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), - } - - builder = builder.Claims(pubClaims) - rawJWT, err := builder.CompactSerialize() - if err != nil { - return trace.Wrap(err) - } - - cfg, err := config.LoadDefaultConfig(ctx) - if err != nil { - return trace.Wrap(err) - } - cfg.Region = "us-east-1" - - p := stscreds.NewWebIdentityRoleProvider( - sts.NewFromConfig(cfg), - roleARN, - IdentityToken(rawJWT), - ) - - cfg2, err := config.LoadDefaultConfig(ctx, config.WithCredentialsProvider(p)) - if err != nil { - return trace.Wrap(err) - } - cfg2.Region = "us-east-1" - - // RDS List DBs - rdsClient := rds.NewFromConfig(cfg2) - rdsDBs, err := rdsClient.DescribeDBInstances(ctx, &rds.DescribeDBInstancesInput{}) - if err != nil { - return trace.Wrap(err) - } - - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"Status", "Name", "IAMAuth", "Engine", "EngineVersion", "MasterUserName", "DBName", "Tags", "ARN", "Addr", "Port"}) - - for _, db := range rdsDBs.DBInstances { - table.Append([]string{ - *db.DBInstanceStatus, - *db.DBInstanceIdentifier, - fmt.Sprintf("%t", db.IAMDatabaseAuthenticationEnabled), - *db.Engine, - *db.EngineVersion, - *db.MasterUsername, - stringOrNil(db.DBName), - fmt.Sprintf("%v", db.TagList), - *db.DBInstanceArn, - *db.Endpoint.Address, - fmt.Sprintf("%d", db.Endpoint.Port), - }) - } - table.Render() // Send output - - return c.String(http.StatusOK, "hello!") - }) - - e.Logger.Fatal(e.Start(":1323")) + e := echo.New() + e.Debug = true + e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ + Format: "method=${method}, uri=${uri}, status=${status}\n", + })) + + block, _ := pem.Decode([]byte(privateKey)) + parseResult, _ := x509.ParsePKCS8PrivateKey(block.Bytes) + key := parseResult.(*rsa.PrivateKey) + + e.GET("/v1/.well-known/openid-configuration", func(c echo.Context) error { + discovery := &DiscoveryConfiguration{ + Issuer: "https://" + URL, + JwksURI: "https://" + URL + "/.well-known/jwks", + ClaimsSupported: []string{"sub", "aud", "exp", "iat", "iss", "jti", "nbf", "ref"}, + IDTokenSigningAlgValuesSupported: []string{"RS256"}, + ResponseTypesSupported: []string{"id_token"}, + ScopesSupported: []string{"openid"}, + SubjectTypesSupported: []string{"public", "pairwise"}, + } + + return c.JSON(http.StatusOK, discovery) + }) + + e.GET("/v1/.well-known/jwks", func(c echo.Context) error { + keyset := &jose.JSONWebKeySet{ + Keys: []jose.JSONWebKey{ + { + KeyID: "id", + Algorithm: "RS256", + Use: "sig", + Key: &key.PublicKey, + }, + }, + } + + return c.JSON(http.StatusOK, keyset) + }) + + e.GET("/aws", func(c echo.Context) error { + ctx := c.Request().Context() + + key := jose.SigningKey{Algorithm: jose.RS256, Key: key} + + // create a Square.jose RSA signer, used to sign the JWT + var signerOpts = jose.SignerOptions{} + signerOpts.WithType("JWT") + rsaSigner, err := jose.NewSigner(key, &signerOpts) + if err != nil { + return trace.Wrap(err) + } + + builder := jwt.Signed(rsaSigner) + + pubClaims := jwt.Claims{ + Issuer: "https://" + URL, + Subject: "some-subject", + ID: "id1", + Audience: jwt.Audience{"discover.teleport"}, + IssuedAt: jwt.NewNumericDate(time.Now()), + Expiry: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), + } + + builder = builder.Claims(pubClaims) + rawJWT, err := builder.CompactSerialize() + if err != nil { + return trace.Wrap(err) + } + + cfg, err := config.LoadDefaultConfig(ctx) + if err != nil { + return trace.Wrap(err) + } + cfg.Region = "us-east-1" + + p := stscreds.NewWebIdentityRoleProvider( + sts.NewFromConfig(cfg), + roleARN, + IdentityToken(rawJWT), + ) + + cfg2, err := config.LoadDefaultConfig(ctx, config.WithCredentialsProvider(p)) + if err != nil { + return trace.Wrap(err) + } + cfg2.Region = "us-east-1" + + // RDS List DBs + rdsClient := rds.NewFromConfig(cfg2) + rdsDBs, err := rdsClient.DescribeDBInstances(ctx, &rds.DescribeDBInstancesInput{}) + if err != nil { + return trace.Wrap(err) + } + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Status", "Name", "IAMAuth", "Engine", "EngineVersion", "MasterUserName", "DBName", "Tags", "ARN", "Addr", "Port"}) + + for _, db := range rdsDBs.DBInstances { + table.Append([]string{ + *db.DBInstanceStatus, + *db.DBInstanceIdentifier, + fmt.Sprintf("%t", db.IAMDatabaseAuthenticationEnabled), + *db.Engine, + *db.EngineVersion, + *db.MasterUsername, + stringOrNil(db.DBName), + fmt.Sprintf("%v", db.TagList), + *db.DBInstanceArn, + *db.Endpoint.Address, + fmt.Sprintf("%d", db.Endpoint.Port), + }) + } + table.Render() // Send output + + return c.String(http.StatusOK, "hello!") + }) + + e.Logger.Fatal(e.Start(":1323")) } func stringOrNil(s *string) string { - if s == nil { - return "" - } - return *s + if s == nil { + return "" + } + return *s } ``` From f6ef36301bcd758aafc21041f5ed58d77bf215a1 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Tue, 4 Apr 2023 18:16:35 +0100 Subject: [PATCH 13/14] add rfd number --- ...ion-using-oidc.md => 0119-aws-api-integration-using-oidc.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename rfd/{9999-aws-api-integration-using-oidc.md => 0119-aws-api-integration-using-oidc.md} (99%) diff --git a/rfd/9999-aws-api-integration-using-oidc.md b/rfd/0119-aws-api-integration-using-oidc.md similarity index 99% rename from rfd/9999-aws-api-integration-using-oidc.md rename to rfd/0119-aws-api-integration-using-oidc.md index cd0c0742e6ca4..bd9049318f074 100644 --- a/rfd/9999-aws-api-integration-using-oidc.md +++ b/rfd/0119-aws-api-integration-using-oidc.md @@ -3,7 +3,7 @@ authors: Marco Dinis (marco.dinis@goteleport.com) state: draft --- -# RFD 999 - AWS API Integration using OIDC +# RFD 119 - AWS API Integration using OIDC ## Required Approvals From 036c2b7d20e4e6eb1a83f247a1de6920a7ad6513 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Wed, 5 Apr 2023 16:27:21 +0100 Subject: [PATCH 14/14] remove status from integration --- rfd/0119-aws-api-integration-using-oidc.md | 26 ++-------------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/rfd/0119-aws-api-integration-using-oidc.md b/rfd/0119-aws-api-integration-using-oidc.md index bd9049318f074..fc9b8d0a27983 100644 --- a/rfd/0119-aws-api-integration-using-oidc.md +++ b/rfd/0119-aws-api-integration-using-oidc.md @@ -80,23 +80,6 @@ message IntegrationSpecV1 { // AWSOIDC contains the specific fields to handle the AWS OIDC Integration subkind AWSOIDCIntegrationSpecV1 AWSOIDC = 1; } - - // IntegrationStatus contains the current integration status. - enum IntegrationStatus { - INTEGRATION_STATUS_UNSPECIFIED = 0; - - // Integration is not running because it was just created or was disabled by the user. - INTEGRATION_STATUS_PAUSED = 1; - - // Integration is running. - INTEGRATION_STATUS_RUNNING = 2; - - // Integration has an error and that should be fixed before receiving requests. - INTEGRATION_STATUS_ERROR = 3; - } - - // Status contains the current Integration Status - IntegrationStatus status = 2; } // AWSOIDCIntegrationSpecV1 contains the spec properties for the AWS OIDC SubKind Integration. @@ -322,11 +305,8 @@ Described [above](#user_s-point-of-view). #### Web API Integration resource will have the usual CRUD operations via Web API. -The user can only update two fields: +The user can only update one field: - awsOIDC.roleARN: to set the AWS Role that should be used for this Integration -- status: - - Paused: when the Integration should not be used, to support a disable operation - - Running: when the Integration is running HTTP API: ``` @@ -344,8 +324,7 @@ JSON representation: "subkind": "aws-oidc", "awsOIDC": { "roleARN": "arn:aws:123:TeleportOIDC" - }, - "status": "IntegrationStatusRunning" + } } ``` @@ -416,7 +395,6 @@ spec: subkind_spec: aws_oidc: role_arn: arn:aws:123:TeleportOIDC - status: INTEGRATION_STATUS_RUNNING $ tctl create aws-integration.yaml ```