Can I impose a restriction on an IAM policy to run on a specific account only? I have searched for documentation or examples online but could not find anything on it.
Edited:
There are multiple accounts and similar policies to implement, each with a different restriction. In such cases, to prevent any mixing up while implementation of policies; I want to ensure that there is a restriction that imposed on the policy that tells which AWS account this policy can live in.
CFT:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Policy for XYZ'
Resources:
XYZPolicy:
Type: "AWS::IAM::ManagedPolicy"
Properties:
Description: "Restrictions apply only to Account XYZ"
Path: "/"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "cloudformation:*"
- "cloudtrail:*"
- "cloudwatch:*"
- "ec2:*"
- "sso:*"
- "s3:*"
Resource: "*"
Roles:
-
Ref: "XYZRole"
ManagedPolicyName: "XYZPolicy
By default, a policy only applies to the account it belongs to, although you can enable cross-account policies, so what you're trying to do is basically the default.
If you really want to do this anyways, you may be able try something along the lines of:
"Condition": {
"ArnEquals": {
"iam:PolicyArn": [
"arn:aws:iam::AWS-ACCOUNT-ID:policy/XYZPolicy"
]
}
}
Related
In my serverless.yml file, I want to be able to add iamRoleStatements from two differents files (this cannot change). So I tried doing it like this:
provider:
iamRoleStatements:
- ${file(__environments.yml):dev.iamRoleStatements, ''}
- ${file(custom.yml):provider.iamRoleStatements, ''}
Each of these files have an iamRoleStatements section.
__environments.yml:
dev:
iamRoleStatements:
- Effect: 'Allow'
Action: 'execute-api:Invoke'
Resource: '*'
custom.yml:
provider:
iamRoleStatements:
- Effect: "Allow"
Action:
- lambda:InvokeFunction
Resource:
- "*"
Individually, each of them works great. But when I try to run sls deploy with both of them, I encounter the following error:
iamRoleStatements should be an array of objects, where each object has Effect, Action / NotAction, Resource / NotResource fields. Specifically, statement 0 is missing the following properties: Effect, Action / NotAction, Resource / NotResource; statement 1 is missing the following properties: Effect, Action / NotAction, Resource / NotResource
I searched online and this appears to work for other sections of the serverless file such as resources:
# This works perfectly well.
resources:
- ${file(custom.yml):resources, ''}
- ${file(__environments.yml):resources, ''}
So I wonder if there is any solution to this or if it is something that is not currently supported by the Serverless Framework.
Thanks for your help.
You're going to have to jump through a few hoops to get there.
File Merge Limitations
The serverless framework allows file imports anywhere in the configuration but only merges resources and functions sections.
Your example:
provider:
iamRoleStatements:
- ${file(__environments.yml):dev.iamRoleStatements, ''}
- ${file(custom.yml):provider.iamRoleStatements, ''}
Results in an array of arrays like this:
{
"provider": {
"iamRoleStatements": [
[
{
"Effect": "Allow",
"Action": "execute-api:Invoke",
"Resource": "*"
}
],
[
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": [
"*"
]
}
]
]
}
}
You might be able to submit a very small pull request to rectify this.
IAM Managed Policies using References
It might be possible to define each of your IAM roles as custom resources, and use the iamManagedPolicies provider config to point to each of those resources. Something like:
provider:
name: aws
iamManagedPolicies:
- Ref: DevIamRole
- Ref: CustomIamRole
resources:
- ${file(__environments.yml):resources, ''}
- ${file(custom.yml):resources, ''}
Of course you'd need to change the structure of those two files to be AWS::IAM::Role resources.
Custom IAM Role
The framework also gives you the option to take complete control, which is fully documented.
I hope this helps.
I've tried the following resource in my template:
SigningKey:
Type: AWS::KMS::Key
Properties:
Description: "Auth API signing key"
Enabled: true
# Grant all permissions for root account
KeyPolicy:
Version: "2012-10-17"
Id: "key-default-1"
Statement:
-
Sid: "Enable IAM User Permissions"
Effect: "Allow"
Principal:
- AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
Action: "kms:*"
Resource: "*"
EnableKeyRotation: true
KeyUsage: SIGN_VERIFY
But this gives an error:
The operation failed because the KeyUsage value of the CMK is
SIGN_VERIFY. To perform this operation, the KeyUsage value must be
ENCRYPT_DECRYPT.
It's also unclear where to specify the key type (eg. RSA_2048) in the template from the docs.
According to AWS CloudFormation, you specify key type in KeySpec field. You can also see what types are currently supported in the document. Also, AWS KMS does not support automatic key rotation on asymmetric CMKs. For asymmetric CMKs, omit the EnableKeyRotation property or set it to false.
Above doc also has example to create asymmetric CMKs that you can refer.
I would like to create an S3 bucket that is configured to work as a website, and I would like to restrict access to the S3 website to requests coming from inside a particular VPC only.
I am using Cloudformation to set up the bucket and the bucket policy.
The bucket CF has the WebsiteConfiguration enabled and has AccessControl set to PublicRead.
ContentStorageBucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: PublicRead
BucketName: "bucket-name"
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
The bucket policy includes two conditions: one condition grants access full access to the bucket when on the office IP, and the other condition grants access through a VPC endpoint. The code is as follows:
ContentStorageBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ContentStorageBucket
PolicyDocument:
Id: BucketPolicy
Version: '2012-10-17'
Statement:
- Sid: FullAccessFromParticularIP
Action:
- s3:*
Effect: "Allow"
Resource:
- !GetAtt [ ContentStorageBucket, Arn ]
- Fn::Join:
- '/'
- - !GetAtt [ ContentStorageBucket, Arn ]
- '*'
Principal: "*"
Condition:
IpAddress:
aws:SourceIp: "x.x.x.x"
- Sid: FullAccessFromInsideVpcEndpoint
Action:
- s3:*
Effect: "Allow"
Resource:
- !GetAtt [ ContentStorageBucket, Arn ]
- Fn::Join:
- '/'
- - !GetAtt [ ContentStorageBucket, Arn ]
- '*'
Principal: "*"
Condition:
StringEquals:
aws:sourceVpce: "vpce-xxxx"
To test the above policy conditions, I have done the following:
I've added a file called json.json to the S3 bucket;
I've created an EC2 instance and placed it inside the VPC referenced in the bucket.
I've made a curl request to the file endpoint http://bucket-name.s3-website-us-east-1.amazonaws.com/json.json from inside the whitelisted IP address, and the request succeeds;
I've made a curl request to the file endpoint from inside the EC2 instance (placed in the VPC), and the request fails with a 403 Access Denied
Notes:
I have made sure that the EC2 instance is in the correct VPC.
The aws:sourceVpce is not using the value of the VPC ID, but it is using the value of the Endpoint ID of the corresponding VPC.
I have also used aws:sourceVpc with the VPC ID, instead of using the aws:sourceVpce with the endpoint ID, but this produced the same results as the one mentioned above.
Given this, I currently am not sure how to proceed in further debugging this. Do you have any suggestions about what might be the problem? Please let me know if the question is not clear or anything needs clarification. Thank you for your help!
In order for resources to use the VPC endpoint for S3, the VPC router must point all traffic destined for S3 to the VPC endpoint. Rather than maintain a list of all of the CIDR blocks that are S3 specific on your own, AWS allows you to use BGP prefix lists which are a first-class resource in AWS.
To find the prefix list for S3 run the following command (your output should match mine, since this should be the same region wide across all accounts, but best to check). Use the region of your VPC.
aws ec2 describe-prefix-lists --region us-east-1
I get the following output:
{
"PrefixLists": [
{
"Cidrs": [
"54.231.0.0/17",
"52.216.0.0/15"
],
"PrefixListId": "pl-63a5400a",
"PrefixListName": "com.amazonaws.us-east-1.s3"
},
{
"Cidrs": [
"52.94.0.0/22",
"52.119.224.0/20"
],
"PrefixListId": "pl-02cd2c6b",
"PrefixListName": "com.amazonaws.us-east-1.dynamodb"
}
]
}
For com.amazonaws.us-east-1.s3, the prefix list id is pl-63a5400a,
so you can then create a route in whichever route table services the subnet in question. The Destination should be the prefix list (pl-63a5400a), and the target should be the VPC endpoint ID (vpce-XXXXXXXX) (which you can find with a aws ec2 describe-vpc-endpoints).
This is trivial from the console. I don't remember how to do this from the command line, I think you have to send a cli-input-json with something like the below, but I haven't tested. this is left as an exercise for the reader.
{
"DestinationPrefixListId": "pl-63a5400a",
"GatewayId": "vpce-12345678",
"RouteTableid": "rt-90123456"
}
I am trying to setup an AWS ALB Ingress Controller using the IRSA method instead of kube2iam. There is however some lack of documentation so I came to a dead end.
What I did so far:
Configured the OIDC provider for my cluster
eksctl utils associate-iam-oidc-provider --cluster devops --approve
Created the proper policy by using the template
Created the IAM service account that will be used by the Ingress Controller and associated the policy
eksctl create iamserviceaccount --name alb-ingress --namespace default --cluster devops --attach-policy-arn arn:aws:iam::112233445566:policy/eks-ingressController-iam-policy-IngressControllerPolicy-1111111111 --approve
Deployed required rbac rules provided
kubectl apply -f rbac-role.yaml
Deployed the AWS Ingress Controller by using this template. Payed attention so the ServiceAccount matches the service account I created previously.
Everything up to here is deployed fine. Now I try to deploy my Ingress service but I get this error (in the controller logs)
kubebuilder/controller "msg"="Reconciler error" "error"="failed to build LoadBalancer configuration due to failed to get AWS tags. Error: AccessDeniedException: User: arn:aws:sts::1122334455:assumed-role/eksctl-devops-nodegroup-ng-1-work-NodeInstanceRole-J08FDJHIWPI7/i-000000000000 is not authorized to perform: tag:GetResources\n\tstatus code: 400, request id: 94d614a1-c05d-4b92-8ad6-86b450407f6a" "Controller"="alb-ingress-controller" "Request"={"Namespace":"superset","Name":"superset-ingress"}
Obviously the node doesn't have the proper permissions for the ALB creation, and I guess that if I attached my policy to the role stated in the log it would work. But that defeats the whole purpose of doing the IRSA method right?
What I would expect is for the Ingress Controller pod to need the appropriate permissions -by using the service account- to create the ALB and not the Node. Am I missing something here?
I've got a similar error (not identical) when using version v1.1.8 of this controller:
kubebuilder/controller "msg"="Reconciler
error"="failed get
WAFv2 webACL for load balancer arn:aws:elasticloadbalancing:...:
AccessDeniedException: User:
arn:aws:sts:::assumed-role/eks-node-group-role/
is not authorized to perform: wafv2:GetWebACLForResource on resource:
arn:aws:wafv2:us-east-2::regional/webacl/*\n\tstatus code:
400, request id: ..."
"controller"="alb-ingress-controller"
"request"={"Namespace":"default","Name":"aws-alb-ingress"}
I'll add it because I think it can help people which search under the same error message.
The reason for the error described above was the fact that version v1.1.7 of this controller needs new IAM permissions in the nodegroup role's *PolicyALBIngress policy.
(!) Be aware that the new IAM permission is required even no wafv2 annotation is used.
Solution 1
Adding the section of wafv2 allow actions to the policy:
{
"Effect": "Allow",
"Action": [
"wafv2:GetWebACL",
"wafv2:GetWebACLForResource",
"wafv2:AssociateWebACL",
"wafv2:DisassociateWebACL"
],
"Resource": "*"
}
Solution 2
WAFV2 support can be disabled by controller flags as mentioned here.
A) If you install it via kubectl, add - --feature-gates=waf=false to the spec -> containers -> args section.
B) If you install it via helm, add --set extraArgs."feature-gates"='waf=false' in helm upgrade command.
Notice that this requirment was already being updated in the eksctl tool (Review also in here).
Additional reference.
So, in case someone comes up to the same problem.
The solution is, when creating the rbac roles, to comment out from the rbac-role.yaml (as provided here) the last part which creates the service account.
Since we already created a service account with eksctl and attached to it the aws policy, we can attach to this service account the rbac permissions also. Then this service account can be used normally in the ingress controller pod to do its magic.
According to the documentation need the permission to CRUD an ALB. You could if you wanted to try giving just the ALB driver Pod a role with permissions create the ALB but I have not tested it and I am not sure it matters, if your entire scheduler has been given access to to use the ALB driver/pod to create these objects on AWS.
I am not using EKS's 3.0's cluster creation tool, instead I have my own CFT that I use to create workers due to my orgs additional security requirements.
I have have created and attached the bellow managed policy to workers that need to create ALB's and it just works.
ALBPolicy:
Type: "AWS::IAM::ManagedPolicy"
Properties:
Description: Allows workers to CRUD alb's
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "acm:DescribeCertificate"
- "acm:ListCertificates"
- "acm:GetCertificate"
Resource: "*"
-
Effect: "Allow"
Action:
- "ec2:AuthorizeSecurityGroupIngress"
- "ec2:CreateSecurityGroup"
- "ec2:CreateTags"
- "ec2:DeleteTags"
- "ec2:DeleteSecurityGroup"
- "ec2:DescribeAccountAttributes"
- "ec2:DescribeAddresses"
- "ec2:DescribeInstances"
- "ec2:DescribeInstanceStatus"
- "ec2:DescribeInternetGateways"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DescribeSecurityGroups"
- "ec2:DescribeSubnets"
- "ec2:DescribeTags"
- "ec2:DescribeVpcs"
- "ec2:ModifyInstanceAttribute"
- "ec2:ModifyNetworkInterfaceAttribute"
- "ec2:RevokeSecurityGroupIngress"
Resource: "*"
-
Effect: "Allow"
Action:
- "elasticloadbalancing:AddListenerCertificates"
- "elasticloadbalancing:AddTags"
- "elasticloadbalancing:CreateListener"
- "elasticloadbalancing:CreateLoadBalancer"
- "elasticloadbalancing:CreateRule"
- "elasticloadbalancing:CreateTargetGroup"
- "elasticloadbalancing:DeleteListener"
- "elasticloadbalancing:DeleteLoadBalancer"
- "elasticloadbalancing:DeleteRule"
- "elasticloadbalancing:DeleteTargetGroup"
- "elasticloadbalancing:DeregisterTargets"
- "elasticloadbalancing:DescribeListenerCertificates"
- "elasticloadbalancing:DescribeListeners"
- "elasticloadbalancing:DescribeLoadBalancers"
- "elasticloadbalancing:DescribeLoadBalancerAttributes"
- "elasticloadbalancing:DescribeRules"
- "elasticloadbalancing:DescribeSSLPolicies"
- "elasticloadbalancing:DescribeTags"
- "elasticloadbalancing:DescribeTargetGroups"
- "elasticloadbalancing:DescribeTargetGroupAttributes"
- "elasticloadbalancing:DescribeTargetHealth"
- "elasticloadbalancing:ModifyListener"
- "elasticloadbalancing:ModifyLoadBalancerAttributes"
- "elasticloadbalancing:ModifyRule"
- "elasticloadbalancing:ModifyTargetGroup"
- "elasticloadbalancing:ModifyTargetGroupAttributes"
- "elasticloadbalancing:RegisterTargets"
- "elasticloadbalancing:RemoveListenerCertificates"
- "elasticloadbalancing:RemoveTags"
- "elasticloadbalancing:SetIpAddressType"
- "elasticloadbalancing:SetSecurityGroups"
- "elasticloadbalancing:SetSubnets"
- "elasticloadbalancing:SetWebACL"
Resource: "*"
-
Effect: "Allow"
Action:
- "iam:CreateServiceLinkedRole"
- "iam:GetServerCertificate"
- "iam:ListServerCertificates"
Resource: "*"
-
Effect: "Allow"
Action:
- "cognito-idp:DescribeUserPoolClient"
Resource: "*"
-
Effect: "Allow"
Action:
- "waf-regional:GetWebACLForResource"
- "waf-regional:GetWebACL"
- "waf-regional:AssociateWebACL"
- "waf-regional:DisassociateWebACL"
Resource: "*"
-
Effect: "Allow"
Action:
- "tag:GetResources"
- "tag:TagResources"
Resource: "*"
-
Effect: "Allow"
Action:
- "waf:GetWebACL"
Resource: "*"
I want to grant access to a group of users to perform certain operations on certain Lambda functions. My Lambdas are already tagged properly to allow this, for instance: "department:hr". Can I tie this together with IAM?
I have seen documentation on conditionals that allow comparison of ResourceTag\* to a value, but these do not seem to be available in the visual editor (which unfortunately I depend on) for Lambda functions.
I want something like this:
"Effect": "Allow",
"Action": [
"lambda:ListFunctions",
"lambda:ListVersionsByFunction",
"lambda:GetLayerVersion",
"lambda:GetEventSourceMapping",
"lambda:GetFunction",
"lambda:ListAliases",
"lambda:GetAccountSettings",
"lambda:GetFunctionConfiguration",
"lambda:GetLayerVersionPolicy",
"lambda:ListTags",
"lambda:ListEventSourceMappings",
"lambda:ListLayerVersions",
"lambda:ListLayers",
"lambda:GetAlias",
"lambda:GetPolicy"
],
"Resource": "*"
"Condition": {
"StringEquals": {
"lambda:ResourceTag/department": "hr"
}
I can't build this in the visual editor and I get syntax errors when I attempt it myself.
I don't believe that lambda:ResourceTag/${TagKey} is a context condition available for any lambda actions (REF: https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awslambda.html).
With that said, incorrect use of context keys typically fails silently. Could you include the full statement? For example, in the above snippet, there is a missing } for the condition.
If your IAM users are tagged with department:hr and if they assume the below IAM role via console, they should be able to access the lambda functions that have been tagged with department:hr.
HRDepartmentLambdaFunctionsAccessRole:
Type: AWS::IAM::Role
Properties:
RoleName: "HRDepartmentLambdaFunctionsAccessRole"
AssumeRolePolicyDocument:
# Allow users in account X to perform operations on lambda functions
Statement:
- Effect: Allow
Principal:
AWS:
- "AWS_ACCOUNT_NUMBER"
Action:
- sts:AssumeRole
Condition:
StringEquals:
aws:PrincipalTag/department:
- hr
Path: /
Policies:
- PolicyName: AllowAccessToLambdaFunctionsInHRDepartment
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- lambda:ListFunctions
- lambda:ListVersionsByFunction
- lambda:GetLayerVersion
- lambda:GetEventSourceMapping
- lambda:GetFunction
- lambda:ListAliases
- lambda:GetAccountSettings
- lambda:GetFunctionConfiguration
- lambda:GetLayerVersionPolicy
- lambda:ListTags
- lambda:ListEventSourceMappings
- lambda:ListLayerVersions
- lambda:ListLayers
- lambda:GetAlias
- lambda:GetPolicy
Resource: '*'
Condition:
StringEquals:
lambda:ResourceTag/department: 'hr'
Ref: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html