Use already existing KMS key in Lambda functions that are managed through SAM/CloudFormation - amazon-web-services

The situation is:
A lambda function is created using a SAM/CloudFormation. A policy is attached to allow this function to access an existing bucket (in the same region). This looks somehow like this:
MyFunction:
Type: AWS::Serverless::Function
Properties:
.....
Policies:
- Statement:
- Effect: Allow
Action:
- "s3:ListBucket"
- "s3:PutObject"
- "s3:GetObject"
Resource:
- "arn:aws:s3:::my-great-existing-bucket"
- "arn:aws:s3:::my-great-existing-bucket/*"
This means: Without modifying the policy of the existing bucket, the newly created lambda-function will now have access to that bucket.
But in this case this already existing bucket is additionally encrypted with an existing customer managed KMS key (again in the same region) so access will still be denied to the Lambda function. The goal would be to add the policy to use that existing key also directly to cloud-formation template.
I found this link:
https://docs.aws.amazon.com/kms/latest/developerguide/iam-policies.html
My interpretation would be, that the named goal would usually be achieved only the other way round:
You need to modify the policy of the KMS-key. But they Key is of course not managed via the Cloud Formation Stack and therefore not manageable here (or am I wrong about that?).
So the only way to achieve it would be to activate general IAM Policies for the KMS-key?
https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default-allow-root-enable-iam
Is that understanding correct?

So the only way to achieve it would be to activate general IAM Policies for the KMS-key?
Yes. That's correct. If your customer managed KMS key does not have it, you have to modify KMS policy to allow lambda role. If you activate general IAM Policies, then you can just modify the lambda execution role with permissions to the KMS key.

Related

IAM PassRole restrictions

I need the permissions to pass an execution role to a Lambda when I create a CF.
So I have given the role used for creating the CF this:
Effect: Allow
Action:
- iam:PassRole
Resource:
- "myexecutionrole"
So now my CF role can pass the execution role to any resource. I want to restrict this. I want it only to be able to pass the role to the Lambda function it is for. So I have been looking into policy conditions, put here I only find solution for restricting the source of the call not the target.
Is that I want possible and how?
You could use iam:AssociatedResourceArn. From docs:
Specifies the ARN of the resource to which this role will be associated at the destination service.

GCP: Generic routine to create IAM Policy Binding given a resource, member, and role

I have a dump of IAM Policies and I want to add a new member to all of them. The problem is that each resource has its own API for setting IAM policies, and so I would need to handle each type of resource individually. So much toil. I want a generic "IAM API" that takes a resource & policy as inputs, and creates the binding. Is such a thing possible?
For reference, the format for my policy dump is:
- policy:
bindings:
- members:
- user:tom#email.com
role: roles/compute.networkUser
etag: BwWfgKQuAFg=
project: projects/800307802527
resource: //compute.googleapis.com/projects/foo-proj/regions/us-central1/subnetworks/sub1
I have a very long list of these records, and I want to iterate through them adding a member "new-member#email.com" to each one. Is there a generic IAM API I can call to add a policy binding to a resource?
As mentioned in the comment, each resource has its own API. There is no "Generic" IAM API to handle your use case. You can however create a feature request through the Public Issue Tracker to make a request for this feature to be implemented.

IAM policy - How to reference resources?

Below is the policy template created to restrict any Principal to do only below actions:
Resources:
MyPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: RulesToCreateUpdatePolicy
ManagedPolicyName: some-policy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "iam:CreatePolicy"
- "iam:DeletePolicy"
- "iam:CreatePolicyVersion"
Resource:
- !Sub "arn:aws:iam::${AWS::AccountId}:policy/xyz-lambda-*"
on a policy resource that starts with name xyz-lambda-.
This policy is assigned to EC2 host, with a role.
Does this policy name(like xyz-lambda-*) supposed to be already exist in AWS, before uploading this policy in AWS?
No, when you are specifying resource in your policy document, that resource doesn't need to exists at all.
If you take into consideration this action
iam:CreatePolicy
together with your resource, what it does is that it grants necessary permissions to create policy with that particular name xyz-lambda-*. It wouldn't make much of sense to require existence of such resource if the policy is granting permissions to create it in the first place.
When you consider the delete action
iam:DeletePolicy
if the resource doesn't exist then it does nothing. Once you create policy with the appropriate name, you will be able to delete it but it doesn't matter whether the policy existed before this ManagedPolicy was created or after or you have deleted and recreated policy with such name any number of times.
Lastly, since you have stated that this policy is attached to EC2 role then it should work without errors. But I would still recommend to grant iam:ListPolicies permission for any resource (policy) discovery that could be performed by an application running on EC2 instance. If you don't allow this action in your policy, your application will not be able to list policies and you would have to design some error prone workaround based on guessing or a strict naming scheme.
Policy name is not important. Resources unique by ARN only. IAM Resources unique within AWS account an if u don't create this resource before it's ok

How do you prevent a Role from being associated with an EC2 without a specific tag?

I created an AWS IAM Role and it included the following
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
Condition:
StringEquals:
ec2:ResourceTag/AppCode: !Sub "${AppCode}"
I verified that my EC2 does contain tag AppCode and it had the value passed in to the CloudFormation.
After associating the Role with the EC2, I was not able to see the role when running 'aws configure list' on the EC2.
After removing the above condition it worked immediately! 'aws configure list' returned the correct results.
What is the correct why to prevent a Role from being associated with EC2 instances, unless they have a specific tag with a specific value?
Thanks
I'm not sure if what you describe is possible, but please keep exploring!
Your policy is saying "Allow the EC2 service to call AssumeRole if the has a particular tag".
The official way to control whether an EC2 instance can be assigned a role is to grant iam:PassRole to the IAM entity that is launching the instance.
If somebody does not have iam:PassRole, then they cannot specify a role when launching an instance. If you want them to be able to use a particular role, you can grant them iam:PassRole for a specific Role, which they can then use when launching an instance.
This method grants the IAM User/Group/Role the permission to select a Role, rather than controlling permissions based on the instance (that doesn't necessarily even exist yet).

AWS Managed Policy Vs Policy

Can someone explain to me the difference between an AWS Policy and an AWS Managed Policy in the context of Cloud Formation?
More specifically, I'm trying to define an auto scaling template where:
Each instance in an auto scale configuration is assigned an IAM Instance Role that has a policy.
The same policy is applied to the user when they try and access these instances.
I'm trying to keep duplication to a minimum and it seems like I may be able to achieve it via a Policy linked to a role, and group of users. The role can then be associated with EC2 Instance via instance profile and users can be added to the groups which in turn are assigned the policy.
Why and under what circumstances would one use a ManagedPolicy?
Thank you for your assistance.
EDIT: It seems like Role requires a policy document irrespective. So even having a separate policy won't really help? Or am I missing something?
AWS::IAM::Role only requires a trust policy. The Policy/Managed Policy can be defined separately.
The difference between AWS::IAM::ManagedPolicy and AWS::IAM::Policy is that AWS::IAM::ManagedPolicy does not require you to assign a Group, Role or User when defining it. AWS::IAM::Policy does. In your use case, you're probably fine using AWS::IAM::Policy.
If I may add, testing Policy creation using CDK v2.12.0, groups, users or roles are not required. iam.ManagedPolicy creates a policy you can share, iam.Policy is created as an inline policy.
new iam.Policy(this, 'testPolicy2', {
statements: policyDocs,
//groups: [s3UserGroup],
policyName: 'testPolicy2'
})
new iam.ManagedPolicy(this, 'testPolicy3', {
statements: policyDocs,
//groups: [s3UserGroup],
managedPolicyName: 'testPolicy3'
})