Where to find External Id for SmsConfiguration in Cognito user pool - amazon-web-services

I use create_user_pool for creating new Cognito user pools. I see there's a SmsConfiguration option which takes an ExternalId.
If you set up MFA for your user pool using the Cognito portal, this External Id (which looks like an UUID) will be used in the automatically generated IAM SMS-Role.
Where do I find/generate the value for ExternalId if I want to manually (using boto3 or AWS CLI) create the user pool and the IAM SMS role?
My MFA setup looks like this:

You're right, it's a UUID that you define in the IAM Role. Here is an example CloudFormation Template with an External ID -
CognitoSMSRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "cognito-idp.amazonaws.com"
Action:
- "sts:AssumeRole"
Condition:
StringEquals:
"sts:ExternalId": 'this-is-my-external-id'
Path: "/"
CognitoSMSPolicy:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: "CognitoSMSPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "sns:publish"
Resource:
- "*"
Roles:
- Ref: CognitoSMSRole
You can also find the External ID in the console.
IAM -> Roles -> Select your Role -> Trusted Relationships

Related

Possible to create a policy and share the policy to role across multiple accounts

I am trying to create a policy in one AWS account and need to share that policy to a role in multiple accounts (Prod, Dev, Sandbox).
And I can add the AWS accounts number manually and assign AWS Managed Policy to roles and needs to create multiple roles as well.
How can we achieve this?
Here is the code I wrote
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Create a role that authorizes access to users in another account'
Metadata:
Version: 0.7
Parameters:
RoleName:
Type: String
Default: R_EC2-Describe-Instance
MainAccountId:
Type: String
Description: >-
Include the Managed Services Account ID(the account ID where the Main VPC is registered)
Default: 111111111111
MaxLength: 12
MinLength: 12
Resources:
AssumeRole:
Type: AWS::IAM::Policy
Properties:
RoleName: !Ref RoleName
Policies:
-
PolicyName: "CoreSVC-Describe-EC2"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- 'sts:AssumeRole'
Resource: !Join [ "", [ "arn:aws:iam::", !Ref MainAccountId, ":role/R_EC2-Describe-Instance" ] ]
AssumeRolePolicyDocument:
Version: '2012-10-17'
ManagedPolicyName:
- "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAcess"
Statement:
- Effect: Allow
Principal:
"AWS": !Join [ "", [ "arn:aws:iam::", !Ref MainAccountId, ":root" ] ]
Action:
- sts:AssumeRole
Condition: {}
You can't share an IAM Policy with other accounts, as it doesn't have a resource policy to allow it.
The code sample you've shared is sharing the IAM Role with multiple accounts, which is possible via the role's resource/trust policy.
If you want to share the same policy across multiple accounts, then you should probably use CloudFormation StackSets (as mentioned by #ervin-szilagyi), or some other infrastructure-as-code approach.
If you want to share the role with other accounts, then you've already done it. All that's missing is role in those accounts with access to the sts:AssumeRole action so that it can assume the role you've shared in your code.

AWS KMS key cannot be used by ECS container because access is denied

Initial state:
I would like to decrypt values using KMS key inside ECS container. In order to do this TaskDefinition has ExecutionRoleArn which references the following role RoleECSTaskContainer. The setup of the role and KMS key looks like this:
KMSKeyEncryption:
Type: AWS::KMS::Key
Properties:
Enabled: true
EnableKeyRotation: false
KeyPolicy:
Version: 2012-10-17
Statement:
- Principal:
AWS:arn of the users/roles who are allowed to manage this key
Effect: Allow
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kms:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:ScheduleKeyDeletion
- kms:CancelKeyDeletion
- kms:Encrypt*
- kms:Decrypt*
Resource: "*"
- Principal:
AWS: ecs-tasks.amazonaws.com
Effect: Allow
Action:
- kms:Decrypt*
Resource: "*"
PolicyDecryptKms:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: DecryptKmsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowDecryptValues
Effect: Allow
Action:
- kms:Decrypt*
Resource: !GetAtt KMSKeyEncryption.Arn
RoleECSTaskContainer:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2008-10-17
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
RoleName: ECSTaskContainerRole
ManagedPolicyArns:
- !Ref PolicyDecryptKms
When the container is trying to decrypt values using KMS key it gets the following exception:
User: arn:aws:sts::123123123:assumed-role/ECSTaskContainerRole/bc9a5782-9sf8-312a-8z76-0ef29a6e5631 is not authorized to perform: kms:Decrypt on resource: arn:aws:kms:eu-west-1:123123123:key/8c9h2f44-bjvb-4l2d-fkj11-fjdahjEr564182
After some investigation, I found out that it starts working if I change a bit the key policy to allow all principals to decrypt like this:
Principal: "*"
Effect: Allow
Action:
- kms:Decrypt*
Resource: "*"
But this is not a safe way to define key policy because I am allowing everyone to decrypt values using this KMS key.
I assume that I am wrong using ecs-tasks.amazonaws.com as principal. Is this correct? If so which service should I use in this case?
There are two ways to control access to your KMS keys:
By using the key policy - which lets you define access control in a single policy.
By using IAM policies in combination with the key policy - controlling access this way enables you to manage all of the permissions for your IAM identities in IAM.
You can use the key policy alone to control access. However, IAM policies by themselves are not sufficient to allow access to a CMK. You must give an AWS account full access to the CMK to enable IAM policies.
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::111122223333:root"},
"Action": "kms:*",
"Resource": "*"
}
So it depends how you would like to manage your policies. I usually prefer KMS key policies for simplicity. So I'd just set the key policy to grant kms:decrypt permission to the role and remove the managed IAM policy.
KMSKeyEncryption:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Version: 2012-10-17
Statement:
...
- Principal:
AWS: !GetAtt RoleECSTaskContainer.Arn
Effect: Allow
Action:
- kms:Decrypt*
Resource: "*"
RoleECSTaskContainer:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2008-10-17
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
RoleName: ECSTaskContainerRole

AWS assign external role to instance

I have a program that goes through many accounts and does inventory. Right now it is using boto3 and AWS keys.
I would like to move away from aws keys and instead assign role to an instance and use that role to switch accounts.
I know how to assign external role to a user, but I have no idea how to do that with an instance role.
The idea here is to do something like this:
Get list of all accounts from main organization account
For each account assume role with ec2 (and other service) describe role
Get inventory
Switch role to another account.
Any ideas how to accomplish this?
Your method is sound. You would do it as follows:
Create a Main Role in the main account.
Assign this role to the Amazon EC2 instance being used to gather the inventory.
Create a Target IAM Role in each target account.
Assign sufficient permissions to each Target Role to allow the inventory (eg Describe* calls)
Edit the Trust Policy on each Target Role to permit the Main Role to use the Target Role
Your application can then use the Main Role (assigned to the EC2 instance) to call AssumeRole() on each of the Target Roles in the child accounts (as per your step 2).
Thus, your flow is really:
Get list of all accounts from main organization account
For each account:
Assume Role on the target role
Get inventory
You can call org API to list accounts first and the same way you can call for each account with cross-account role
Make sure your Ec2 role has sufficient permissions to assume role for child account
def get_accounts():
sts_role = 'arn:aws:iam::XXX:role/AWSAudit_CrossOrgAccess' # Org Billing API
assumedRoleObject = sts.assume_role(RoleArn=str(sts_role), RoleSessionName="accounts_watcher_lambda" )
credentials = assumedRoleObject['Credentials']
conn = boto3.client( 'organizations', aws_access_key_id=credentials['AccessKeyId'], aws_secret_access_key=credentials['SecretAccessKey'], aws_session_token=credentials['SessionToken'],)
list_of_accounts = conn.list_accounts()
return list_of_accounts```
## Your Ec2 role looks like
`
YourServerEc2Profile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: '/'
Roles:
- Ref: YourServerEc2Role
YourServerEc2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
-
PolicyName: AuditInstall
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Action:
- "ssm:*",
- "ec2:DescribeImages",
- "cloudwatch:PutMetricData",
- "ec2:DescribeInstances",
- "lambda:InvokeFunction",
- "ec2:DescribeTags",
- "ec2:DescribeVpcs",
- "cloudwatch:GetMetricStatistics",
- "ec2:DescribeSubnets",
- "ec2:DescribeKeyPairs",
- "cloudwatch:ListMetrics",
- "ec2:DescribeSecurityGroups"
Resource: "*"
Effect: "Allow"
ManagedPolicyArns:
- !Ref YourServerCrossAccount
- arn:aws:iam::aws:policy/ReadOnlyAccess
YourServerCrossAccount:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Resource:
- arn:aws:iam::XXX:role/AWS_CrossAccount
`

Restrict login to Enterprise Google Domain for AWS Federated Identity Pool

I'm using a federation identity pools with aws-amplify (https://aws.github.io/aws-amplify/media/authentication_guide#enabling-federated-identities) and I'd like to restrict the scope of domains to just my google domain organization (ex. johndoe#foobar.com).
There doesn't seem to be a way to lock it down on either the Google API console or the AWS Cognito Identity Pool settings, just a hint that an hd parameter can be appended to the google request to restrict it by domain (which would still require modifying the aws-amplify core package), and it still wouldn't be secure since anyone could just make the same request without the hd and gain access to cognito.
My question is this: is there a way to restrict a google oauth key to only allow #foobar.com email addresses, or to implement the same restriction with aws cognito?
I believe I found a solution (from several quick tests it seems to be working fine)
Don't try to control the hosted domain part via the Trust Relationship
in the Role.
Go to: Cognito / Edit Identity Pool / Authentication Providers
Select Google+
In "Authenticated role selection" select "Choose role with Rules"
Now require claim "hd" to be "equals" to <your-domain>
set "Role resolution" to "DENY"
Source: https://forums.aws.amazon.com/thread.jspa?messageID=527303
Here's a cloudformation stack to set everything (identity pool, roles, etc.) in one go. YOU NEED TO MAKE THE NECESSARY ADJUSTMENTS at all places marked with an EDIT HERE: comment.
AWSTemplateFormatVersion : 2010-09-09
Description : "An Identity Pool stack which uses Google for sign-in"
Resources:
IdentityPool:
Type: AWS::Cognito::IdentityPool
Properties:
IdentityPoolName: identity_pool_a
AllowUnauthenticatedIdentities: false
SupportedLoginProviders:
# EDIT HERE:
"accounts.google.com": "11111111111-22222222222222222222222222222222.apps.googleusercontent.com"
IdentityForbiddenRole:
Type: AWS::IAM::Role
Properties:
MaxSessionDuration: 3600
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref IdentityPool
ForAnyValue:StringLike:
"cognito-identity.amazonaws.com:amr": unauthenticated
Policies:
- PolicyName: None
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Deny
Action: "*"
Resource: "*"
IdentityAllowedRole:
Type: AWS::IAM::Role
Properties:
MaxSessionDuration: 3600
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref IdentityPool
ForAnyValue:StringLike:
"cognito-identity.amazonaws.com:amr": authenticated
Policies:
- PolicyName: UserPermissions
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
# EDIT HERE:
Action: "s3:GetObject"
# EDIT HERE:
Resource: "arn:aws:s3:::my-bucket/*"
RoleAttachment:
Type: AWS::Cognito::IdentityPoolRoleAttachment
Properties:
IdentityPoolId: !Ref IdentityPool
Roles:
unauthenticated: !GetAtt IdentityForbiddenRole.Arn
authenticated: !GetAtt IdentityForbiddenRole.Arn
RoleMappings:
accounts.google.com:
AmbiguousRoleResolution: Deny
Type: Rules
RulesConfiguration:
Rules:
- Claim: hd
MatchType: Equals
# EDIT HERE:
Value: mydomain.com
RoleARN: !GetAtt IdentityAllowedRole.Arn

The new key policy will not allow you to update the key policy in the future

The title says it all. I am getting this error whenever I try to create a KMS key via an AWS CloudFormation template. I am creating the template as an IAM user with administrative permissions, and I want the key to be manageable by any IAM user in the same AWS account with KMS permissions. I am using the following YAML resource definition for the key:
LambdaKmsKey:
Type: AWS::KMS::Key
Properties:
Enabled: true
KeyPolicy:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: kms:*
Principal:
AWS: <Principle>
And yet, NONE of the following values for <Principal> are working, even if I try to create the stack as the root user!
!Join [ "", [ "arn:aws:iam::", !Ref "AWS::AccountId", ":root" ] ]
!Join [ "", [ "arn:aws:sts::", !Ref "AWS::AccountId", ":root" ] ]
!Ref "AWS::AccountId"
I can't just hardcode my user name for the Principal because I want this template to be instantiable by anyone with stack creation permissions. Does anyone know how to resolve this enormously frustrating situation? Thanks in advance.
EDIT:
I should mention that I no longer define KMS Key policies in CloudFormation Templates. In fact, I now avoid defining any security resources in my CF Templates at all, such as IAM entities, policies, and ACM certificates. My reasons for this are described in this GitHub issue.
You are missing the Resource: "*" attribute. This worked for me:
LambdaKmsKey:
Type: AWS::KMS::Key
Properties:
Enabled: true
KeyPolicy:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: kms:*
Resource: "*"
Principal:
AWS: !Join [ "", [ "arn:aws:iam::", !Ref "AWS::AccountId", ":root" ] ]
The Resource: "*" is required and is the only possible value:
Resource – (Required) In a key policy, you use "*" for the resource, which means "this CMK." A key policy applies only to the CMK it is attached to.
See https://aws.amazon.com/premiumsupport/knowledge-center/update-key-policy-future/ for an example.
In case this helps someone, be aware of the remark in https://aws.amazon.com/premiumsupport/knowledge-center/update-key-policy-future/
Important: Be sure that the key policy that you create allows the current user to administer the CMK.
I was having this issue while deploying my template from a pipeline and the proposed solutions did not work for me. The role used to deploy the template had the corresponding kms permissions, but it needed to be also in the principal of a the key policy!
- Effect: Allow
Action: kms:*
Resource: "*"
Principal:
AWS:
- !Sub arn:aws:iam::${AWS::AccountId}:role/PipelineRole
LambdaKmsKey:
Type: AWS::KMS::Key
Properties:
Description: Key for Lambda function
Enabled: True
KeyPolicy:
Version: '2012-10-17'
Id: key-consolepolicy-3
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: arn:aws:iam::AwsAccountId:root
Action: kms:*
Resource: "*"
- Sid: Allow use of the key
Effect: Allow
Principal:
AWS:
Fn::GetAtt: [ IamRoleLambdaExecution, Arn ]
Action:
- kms:Decrypt
- kms:Encrypt
Resource: "*"
This policy is bit dangerous because it gives any user or role under the account with kms:decrypt permission to decrypt and view the key, which is not safe and it fails pen testing.
If you want to take away permission to decrypt.
LambdaKmsKey:
Type: AWS::KMS::Key
Properties:
Description: Key for Lambda function
Enabled: True
KeyPolicy:
Version: '2012-10-17'
Id: key-consolepolicy-3
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: arn:aws:iam::AwsAccountId:role/sudo
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kmzs:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:ScheduleKeyDeletion
- kms:CancelKeyDeletion
- kms:Encrypt
Resource: "*"
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: arn:aws:iam::AwsAccountId:role/admin
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kmzs:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:ScheduleKeyDeletion
- kms:CancelKeyDeletion
- kms:Encrypt
Resource: "*"
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: arn:aws:iam::AwsAccountId:root
Action:
- kms:List*
- kms:Get*
- kms:Encrypt
Resource: "*"
- Sid: Allow use of the key
Effect: Allow
Principal:
AWS:
Fn::GetAtt: [ IamRoleLambdaExecution, Arn ]
Action:
- kms:Decrypt
- kms:Encrypt
Resource: "*"
This way I am giving all other permission except decrypt to sudo and admin roles(Make sure you have those roles present)
and I am giving list, get and encrypt permission to roles and users that has list, get and encrypt permissions.
I got the same error when I tried creating CMK through lambda. So I add the lambda role arn in key policy while creating the key.
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn of lambda role"
}
}