To access resources inside an AWS account from Azure, there is the possibility of using an IAM User, creating Access Key Id and Secret Access Key.
This solution comes with the disadvantage of static credentials.
In an enterprise setting and in the security best practice sense as well, it is recommended to regularly rotate ones secrets and credentials.
Rotating those credentials results in a lot of overhead and boilerplate code with the possibility of breaking the functionality, especially if multiple parties are involved.
Azure and AWS make it possible to circumvent static credentials by using Azure Managed Identities on one side and AWS Identity Provider on the other. This post goes into more detail. Some Azure Services, like Azure Synapse, do not allow to use Managed Identities. Instead you can use an Azure App Registration to authenticate against AWS.
Create an Azure App Registration pass the Application ID URI, Azure Active Directory Tenant Id and Thumbprint into an AWS CloudFormation Template.
The Thumbprint has to be generated once by going into the AWS Console -> IAM
-> Identity Providers
-> Add provider
-> OpenID Connect
, enter the Provider URL https://sts.windows.net/[your-tenant-id]
and click on Get thumbprint
.
AppRegistrationOidc:
Type: AWS::IAM::OIDCProvider
Properties:
ClientIdList:
- !Ref AppRegistrationIdUri
ThumbprintList:
- !Ref Thumbprint
Url: !Sub 'https://sts.windows.net/${TenantId}/'
AppRegistrationRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument: !Sub
- |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "${AppRegistrationOidc}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"sts.windows.net/${TenantId}/:aud": "${AppRegistrationIdUri}"
}
}
}
]
}
- {
"AppRegistrationOidc": !Ref AppRegistrationOidc,
"AppRegistrationIdUri": !Ref AppRegistrationIdUri,
"TenantId": !Ref TenantId
}
The AssumeRolePolicyDocument is formatted via !Sub and JSON to be able to substitute the TenantId
in the key of the StringEquals
condition.
To assume the role, you have to generate a token with the correct audience and then use the sts:AssumeRoleWithWebIdentity
action.
from azure.identity import ClientSecretCredential
import boto3
credential = ClientSecretCredential(
tenant_id='<tenant-id>',
client_id='<client-id>',
client_secret='<client-secret>'
)
token = credential.get_token('<AppRegistrationIdUri>').token
sts_client = boto3.client('sts')
assumed_role_object = sts_client.assume_role_with_web_identity(
RoleArn='arn:aws:iam::<aws-account-id>:role/<arn of the AppRegistrationRole>',
RoleSessionName='CoolSession',
WebIdentityToken=token)
credentials = assumed_role_object['Credentials']
s3_client = boto3.client(
's3',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken']
)