From AWS to access Azure resources

  • AWS side should have a AWS cognito-user-pool
    • Along with the cognito user pool, a role should be created to bundle with the pool.
      • The role should have cognito-identity:Describe*|Get*|List*|Lookup* access to the cognito user pool.
        • The Get* includes the GetOpenIdTokenForDeveloperIdentity
        • This is typically done by IAM policy
          • The policy should have the cognito user pool as the resource
          • Then, the policy could be added to the IAM role definition as the inline_policy.
    • Note the developer_provider_name used, we will use it later.
  • For the newly created role, you may also want to add IAM policy to allow other roles (i.e. existing roles, like the one assigned to your EC2 hosts or other services) to assume the newly created role.
  • On the Azure side, you will need to have a User Assigned Managed Identity which will be impersonated by your AWS IAM roles through the AWS cognito user pool.
    • You can grant permissions to the User Assigned Managed Identity to access specific Azure resources by Role Assigments.
  • You will need a create a azurerm_federated_identity_credential terraform to allow your cognito pool to assume the User Assigned Managed Identity.
    • The issuer should be “https://cognito-identity.amazonaws.com
    • The audience should be your AWS cognito user pool’s ID (which is part of your pool’s ARN, it starts with the region, like us-west-2)
    • The parent_id is the user assigned managed identity’s ID.
    • The subject is tricky. It is the identity ID AWS assigned to you when you first try GetOpenIdTokenForDeveloperIdentity with the AWS cognito user pool.

The command to GetOpenIdTokenForDeveloperIdentity is:

aws cognito-identity get-open-id-token-for-developer-identity \
   --identity-pool-id <your-pool-id, of form: us-west-2:uuid> \
   --logins <developer_provider_name>=<developer_user_identifier>
  • The logins is a map
  • In the AWS console you will be able to see the ‘developer_user_identifier’ once you tried the GetOpenIdTokenForDeveloperIdentity command for at least once.
  • For the same developer_provider_name:developer_user_identifier pair, the identity_id will be the same (should be this way right?)
  • Then the identity_id shall be the subject for the azurerm_federated_identity_credential.

Workflow

cfg, err := awsconfig.LoadDefaultConfig( ctx)
if err != nil {
  return nil, fmt.Errorf("unable to load aws config %w", err)
}
 
// If you need to use specific egress policy/proxy, use:
// cfg.HTTPClient = <your egress http client>
 
// create AWS stsClient
stsClient := sts.NewFromConfig(cfg)
// assume the role.
// stscreds pkg: https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/credentials/stscreds
// This returns a cred provider, that can refresh the credentials to assume the target role.
assumeRoleCreds := stscreds.NewAssumeRoleProvider(stsClient, <the role bundled with the cognito user pool>)
// create the cred cacher (refresher?)
cfg.Credentials = aws.NewCredentialsCache(creds)
// connect to the cognito identity pool
cognitoSvc := cognitoidentity.NewFromConfig(cfg)
// Get OIDC **functor**
fetcher := func() (token string, error err) {
  tokenResp, err := cognitoSvc.GetOpenIdTokenForDeveloperIdentity(ctx, &cognitoidentity.GetOpenIdTokenForDeveloperIdentityInput{
  		IdentityPoolId: pointer.To(<your cognito pool ID>),
  		Logins: map[string]string{ <your developer_provider_name>: <your developer_user_identifier> },
    },
  )	
  return *tokenResp.Token, err
}
// Use the OIDC fetcher with Azure
azcred, err := azidentity.NewClientAssertionCredential(
	<your azure account tenant ID>,
	<your azure user assigned managed identity client ID>,
	fetcher, // your functor here.
  options, // for HTTP client options (i.e. egress), they go here.
)
 
// Then, use this `azcred` to create Azure clients for your resource accesses.

Azure to AWS

I don’t know yet.