Glue Job Cross-Account secret access failing despite policies - amazon-web-services

Note: I have reviewed other questions and believe this is unique because it specifically pertains to cross-account secrets access using a glue job.
I am having an issue where a glue job, assuming a service role in one account, is unable to access a secret stored in another account, despite my policies which I believe should allow it to do so.
Error I'm seeing (with redacted values): An error occurred (AccessDeniedException) when calling the GetSecretValue operation: Access to KMS is not allowed. This version of secret is not encrypted with the current KMS key.
Question
What about the below setup is causing the permission failure?
Diagram of Current Situation
My Understanding of What Needs to be Done
Based on the AWS docs and a 2018 blog post, I think what we have to do is:
Add a Policy on the secret to allow access to service role
Add a Policy on the CMK to allow service role to decrypt
Add a Policy on Service role to allow access to secret
Add a Policy on Service role to allow CMK decryption
Current Policies
Policy on Secret
{
"Version" : "2012-10-17",
"Statement" : [ {
"Effect" : "Allow",
"Principal" : {
"AWS" : "arn:aws:iam::GLUE_ACCOUNT:role/GLUE_SERVICE_ROLE"
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "*",
"Condition" : {
"ForAnyValue:StringEquals" : {
"secretsmanager:VersionStage" : "AWSCURRENT"
}
}
} ]
}
Policy on CMK
Note that the redacted SECRET_NAME below contains the few characters that AWS appends in the ARN, which it seems we need to include.
{
"Sid": "AllowUseOfTheKey",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::GLUE_ACCOUNT:role/GLUE_SERVICE_ROLE"
},
"Action": ["kms:Decrypt","kms:DescribeKey"],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
},
"StringLike": {
"kms:EncryptionContext:SecretARN": "arn:aws:secretsmanager:us-east-1:SECRET_ACCOUNT:secret:SECRET_NAME"
}
}
}
Policy Statements Attached to Glue Service Role in Glue Account
{
"Sid": "AllowGetSecretValue",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": [
"arn:aws:secretsmanager:us-east-1:SECRET_ACCOUNT:secret:SECRET_NAME"
]
},
{
"Sid": "AllowKMSDecrypt",
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:us-east-1:SECRET_ACCOUNT:key/CMK_KEY_ID"
]
},
Trust policy on the service role
Just to confirm that the glue job does indeed seem to have the authority to assume the service role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "glue.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Possible Next Steps
As thought experiments, I'm considering doing the below just to see if it works:
Removing the condition in the secret policy
Removing the conditions in the CMK policy
Adding kms:DescribeKey to the Service Account policy as well, though I don't think that's going to resolve things.

As sometimes happens with these involved questions, the piece of information to answer the question was found outside of the information I'd provided, despite my best efforts.
The solution was two-fold:
The authorization error that was part of the original question wasn't due to authentication access at all. It was because the code that used boto3 specified the name of the secret instead of the full ARN. Of course secrets manager wouldn't magically know that secret was in a different account.
A surprising thing in this case is that AWS threw an unauthorized exception, and not a not found exception, which would have been infinitely more useful to our efforts.
Once that was fixed, we saw the error that is currently in the ticket, around encrypting the CMK. Apparently when we changed the CMK, we did not select to automatically create a new version of the secret with that CMK. A simple edit and save of the secret by an authorized user was enough to re-encrypt it with the chosen CMK and resolve the issue.

Related

An error occurred (InvalidParameter) when calling the ImportImage operation: The service role vmimport does not exist

I am trying to import a disk image into AWS, for EC2 instance launching. I follow the guide as stated and fulfill all the prerequisites as stated. However I am faced with an error that I've been trying (unsuccessfully) to debug. The error is as follows. An error occurred (InvalidParameter) when calling the ImportImage operation: The service role vmimport provided does not exist or does not have sufficient permissions However when I check the permissions of the vmimport role it has all necessary permissions for EC2 and S3! My aws cli user also has full privileges to EC2 and S3. I've tried many different solutions to this problem, including, 1. Making the S3 bucket public, 2. Adding an access policy so that my AWS cli user had permissions to access the bucket. Everything I have tried still returns this exact same error message... I'm thinking there might be a region problem? I'm using us-east-2 in my AWS cli user configuration, and in the S3 buckets region. Is there something else I have not considered?P.S. I'm trying to import an OVA 1 format vm image.
Here is my trust policy
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "vmie.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals":{
"sts:Externaloid": "vmimport"
}
}
}
]
}
and my roles policy
"Version":"2012-10-17",
"Statement":[
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::MY-IMPORT-BUCKET",
"arn:aws:s3:::MY-IMPORT-BUCKET/*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:PutObject",
"s3:GetBucketAcl"
],
"Resource": [
"arn:aws:s3:::MY-EXPORT-BUCKET",
"arn:aws:s3:::MY-EXPORT-BUCKET/*"
]
},
{
"Effect": "Allow",
"Action": [
"ec2:ModifySnapshotAttribute",
"ec2:CopySnapshot",
"ec2:RegisterImage",
"ec2:Describe*"
],
"Resource": "*"
}
]
}
And finally the containers.json
[
{
"Description": "My Special OVA",
"Format": "ova",
"Url": "s3://MY-IMPORT-BUCKET/VM.ova"
}
]
UPDATE: After investigating the problem further, I found that the role vmimport last access was "Not accessed", i.e. never, meaning that the role is not even being attempted to be used! So this error is clearly saying that it does not exist (it can't find the service role). In the final command there is nothing in the command that suggests that vmimport is going to be used, neither in the containers.json . I thought this was the purpose of allowing vmie.amazonaws.com to take control. Clearly it isn't assuming the role, so I need to investigate into this and sts.
The problem is in your(my) Trust Policy.json file. If you notice the conditions for it to assume the role, is that the Externaloid must be equal to vmimport. There is an added o in the attribute that it is checking, this will always be false and so vmie can never assume the role. Remove the o from the trust policy and try again and your policy works.
I had exactly the same scenario, you need to create vmimport role as described here (AWS docs):
https://docs.aws.amazon.com/vm-import/latest/userguide/required-permissions.html

AWS: Enforce MFA for Console users but not CLI

I am trying to give admin rights to a specific user group and enforcing MFA for the same group. MFA should be only enforced for console users though, not when using the AWS CLI.
These are the policies I have been testing with:
Policy 1 - Administrator access granted if MFA
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAdminAccessIfSignedInWithMFA",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
Policy 2 - Still, allow the user to set up MFA in case it is not yet active
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowViewAccountInfo",
"Effect": "Allow",
"Action": "iam:ListVirtualMFADevices",
"Resource": "*"
},
{
"Sid": "AllowManageOwnVirtualMFADevice",
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice"
],
"Resource": "arn:aws:iam::*:mfa/${aws:username}"
},
{
"Sid": "AllowManageOwnUserMFA",
"Effect": "Allow",
"Action": [
"iam:DeactivateMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ResyncMFADevice"
],
"Resource": "arn:aws:iam::*:user/${aws:username}"
}
]
}
This last policy was adapted from this one.
The official documentation for aws:MultiFactorAuthPresent says, as I understand it, that the combination of "Allow", "BoolIfExists" and "true" should work well for my purpose:
This condition matches either if the key exists and is present or if the key does not exist. This combination of Allow, BoolIfExists, and true allows requests that are authenticated using MFA, or requests that cannot be authenticated using MFA. This means that AWS CLI, AWS API, and AWS SDK operations are allowed when the requester uses their long-term access keys. This combination does not allow requests from temporary credentials that could, but do not include MFA.
If you are wondering why I'm not using any (seemingly simpler) policy containing a "Deny" effect, like:
"Effect" : "Deny",
"Condition" : { "BoolIfExists" : { "aws:MultiFactorAuthPresent" : "false" } }
...the reason is:
This combination of Deny, BoolIfExists, and false denies requests that are not authenticated using MFA. Specifically, it denies requests from temporary credentials that do not include MFA. It also denies requests that are made using long-term credentials, such as AWS CLI or AWS API operations made using access keys. The *IfExists operator checks for the presence of the aws:MultiFactorAuthPresent key and whether or not it could be present, as indicated by its existence. Use this when you want to deny any request that is not authenticated using MFA. This is more secure, but can break any code or scripts that use access keys to access the AWS CLI or AWS API.
Everything works as expected, except for when I try to access resources using the AWS CLI (with an access key).
Am I missing something or is the documentation misleading?
PS: I would like to avoid having separate user groups for console and CLI users.

AWS allow any user of a specific account to send messages to a queue

I am trying to configure the SQS policy for a queue to authorize all principles of an account to send messages to this queue, according to the documentation here:
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "Sqs policy1",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789:root"
]
}
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:eu-west-1:123456789:my_queue"
}
]
}
Will this allow any principle of this account to send messages to my_queue or will it only allow the root user?
Or should I use the below policy with a condition instead?
{
"Version": "2012-10-17",
"Id": "sqspolicy",
"Statement": [
{
"Sid": "Sqs policy1",
"Effect": "Allow",
"Principal": {
"AWS": "*"
}
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:eu-west-1:123456789:my_queue"
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "123456789"
}
}
}
]
}
TIA
The documentation says:
When you use an AWS account identifier as the principal in a policy, you delegate authority to the account. All identities inside the account can access the resource if they have the appropriate IAM permissions attached to explicitly allow access. This includes IAM users and roles in that account.
According to this, your first approach will allow all of your users to send messages.
Only first policy is valid. The second policy will not work, the way you may think. The reason is that aws:SourceAccount is only used for service-to-service requests, not IAM users or roles. The most common example of when aws:SourceAccount is used is for S3:
For example, when an Amazon S3 bucket update triggers an Amazon SNS topic post, the Amazon S3 service invokes the sns:Publish API operation. The bucket is considered the source of the SNS request and the value of the key is the account ID associated with the bucket.
Send-messages requests made by IAM users/roles in the second account will be denied because for these entities there is no aws:SourceAccount.

AWS IAM Policy grant permissions for some EC2 instances

I want to restrict access for a specific user to see just few EC2 instances. I created a new user in IAM Roles and I attached a new Policy to it. The content of that Policy is attached below. I tried to look over documentation and to do it myself like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": [
"arn:aws:ec2:eu-west-1:ACCOUNT_ID:instance/i-INSTANCE_ID1",
"arn:aws:ec2:eu-west-1:ACCOUNT_ID:instance/i-INSTANCE_ID2"
]
}
]
}
I placed my region,ACCOUNT_ID(the owner id, not of the new user created) and instance-id, but when I connect with that user and I go to list all Instances I got this An error occurred fetching instance data: You are not authorized to perform this operation..
After I placed the code in JSON editor, in Policy Review step I got this message:
This policy defines some actions, resources, or conditions that do not
provide permissions. To grant access, policies must have an action
that has an applicable resource or condition. For details, choose Show
remaining Learn more
The AWS documentation mention exactly the same configuration or these examples.
I assume you connect as that user in the console (but it would be the same with CLI) Here is what I think is happening:
To list all the instances, the console most probably calls the DescribeInstances API. As per the list of action/resources/tags that can be used in IAM policy, this API does not support the resource filter in IAM.
This means your user has no authorization to list instances and they will not be shown in the console. You can validate this theory by using the CLI to request the details of a specific instance id, if my hypothesis is correct, it will be authorized.
As DescribeInstances can not be restricted by resource or tags, I don't think it is possible to filter the instance list for a user.
To have the console working, you'll need to add the following statement in your IAM policy
"Statement": [
{ your existing statement },
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*"
}
]
Please report if I was right :-) The example you mentioned in your question shows exactly that : Resources = * on DescribeInstances and Resources specific InstanceId on other operations.
The previous answer is wrong, you can Conditionally allow access to ec2:DescribeInstances by tag names. It's an AWS best practice as well. Also explicitly deny access to the ec2:CreateTags and ec2:DeleteTags actions to prevent users from creating or deleting tags to take control of the instance.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/UserName": "${aws:username}"
}
}
},
{
"Effect": "Deny",
"Action": [
"ec2:CreateTags",
"ec2:DeleteTags"
],
"Resource": "*"
}
]
}
DescribeInstances action does not support condition.
https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html

Is it possible to specify a pattern for an AWS role Trust Relationship

I want to allow some roles from a different account to assume a role in my account. I don't want to specify the roles one by one, because they're prone to change frequently.
I came up with this policy for the Trust Relationship, which should allow any role which name ends with _my_suffix, but it doesn't work (access is denied):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_NR_A:root"
},
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:iam::ACCOUNT_NR_A:role/*_my_suffix"
}
},
"Action": "sts:AssumeRole"
}
]
}
On the other hand, this policy works but it's too open, as it allows any user/role in account A to assume my role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_NR_A:root"
},
"Action": "sts:AssumeRole"
}
]
}
So, is there any way to allow only a set of roles without being explicitly specified?
I encountered the same use-case recently. None of the responses resolved this for me.
Charli, your original solution is valid but I needed some tweaks get it to work, namely, I needed to replace 'ArnLike' with 'stringLike' and switch 'aws:SourceArn' to use 'aws:PrincipalArn':
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<ACCOUNT_ID>:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::<ACCOUNT_ID>:role/test-role-name-*"
}
}
}
It is not possible to use wildcard in the trust policy except "Principal" : { "AWS" : "*" } . The reason being when you specify an identity as Principal, you must use the full ARN since IAM translates to the unique ID e.g. AIDAxxx (for IAM user) or AROAxxx (for IAM role). Below is the from document:
If your Principal element in a role trust policy contains an ARN that
points to a specific IAM user, then that ARN is transformed to the
user's unique principal ID when the policy is saved. This helps
mitigate the risk of someone escalating their privileges by removing
and recreating the user. You don't normally see this ID in the
console, because there is also a reverse transformation back to the
user's ARN when the trust policy is displayed.
This seems to an issue with delegating access to trusting account(your account) and not the trusted account(_my_suffix - AWS account). These are few things that you can check in the following URL.
Link: https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html
Thanks