Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Determining a minimal IAM policy required to perform a terraform run #2834

Closed
gtmtech opened this issue Jul 23, 2015 · 38 comments
Closed

Determining a minimal IAM policy required to perform a terraform run #2834

gtmtech opened this issue Jul 23, 2015 · 38 comments

Comments

@gtmtech
Copy link

gtmtech commented Jul 23, 2015

I am trying to create a minimal IAM policy which can govern the CRUD of my defined terraform resources in AWS, so I can run terraform with my configuration.

I couldn't find any guidance on this, so I started off by creating an IAM policy with no access, hooking up cloudtrail and cloudwatch logs, and then going through the creation of a VPC (as an example), and watching for what actions were unauthorized, and slowly piecing together an IAM profile which would allow terraform to CRUD a VPC.

The job of tracking which Actions need to be allowed would be made a lot easier if under TF_LOG=true, the debugger would print out which action it was trying to do at the point it got a NotAuthorized.

It also struck me that by looking at the terraform code, that these are all available from the terraform code itself, if you can be bothered to walk through it ...

e.g.
conn.CreateVPC
conn.DescribeVPCAttribute
conn.DescribeRouteTables

I wonder if relevant IAM policies could be autogenerated somehow from this.

In any case a little line of debug present would help millions.

Thanks

@gilesbutler
Copy link

+1 for this.

I'm getting this error Error launching source instance: UnauthorizedOperation: You are not authorized to perform this operation.

If I give the AWS user full access then terrafom apply works. I've looked through the docs but can't find anything on setting the correct IAM policy for Terraform. The Packer docs have an example policy with minimum required policy permissions for IAM though.

@gtmtech
Copy link
Author

gtmtech commented Jul 28, 2015

Here is an attempt to parse out what each resource does, even though some resources are chained. It is in Resource:Actions format, and the Actions are the actions in aws go lib, rather than ec2 actions but they correlate very closely. Might be of help

http://pastebin.com/Xm39eh9q

@gilesbutler
Copy link

Thanks for the response @gtmtech unfortunately I can't make sense of that but I appreciate you trying to help.

@gtmtech
Copy link
Author

gtmtech commented Jul 30, 2015

I'm still working on something a bit more coherent for my usecase - hopefully it will be useful to you too.. will keep you posted

@gilesbutler
Copy link

Excellent thanks @gtmtech

@wolfspyre
Copy link

wolfspyre commented Jul 31, 2015 via email

@gtmtech
Copy link
Author

gtmtech commented Aug 15, 2015

In working on this myself, I realised that in practice you want to define multiple terraform policies, otherwise terraform is just too much of a powerful tool and you could accidentally wreck your infrastructure if not careful.

As such, with the aws resources I use, I've defined a "terraform builder" policy which allows my team to build stuff, and a separate "terraform destroyer" policy, which allows people to destroy stuff, and must be used with much greater caution (imagine for example accidentally destroying all your production databases).

I've gone through the code for the resources I use, and split up the actions into CREATE, READ, UPDATE, DELETE (CRUD) operations. A terraform builder policy would then typically be the amalgamation of the CREATE+READ rules. Perhaps a terraform updater policy could be the CREATE+READ+UPDATE rules, and finally the destroyer policy would be READ+UPDATE+DELETE.

I would suggest that we build a database of files (one per aws_resource in terraform), that document the CREATE,READ,UPDATE,DELETE ec2 IAM rules which must be allowed for terraform to do its job, then a simple tool or addition to the terraform cmdline could spit out your minimal IAM policy.

It's not perfect of course - for example when terraform creates a security group, it also revokes the default security group rule , which is a DELETE level operation, so in order to create stuff, you do need a couple of delete privileges. But I've found overall this really protects the infrastructure and the team from mishaps - because in our infrastructure now, it is impossible to accidentally delete what we've built.

Anyway, here are the list of rules I've managed to do so far - there may be a couple of bugs, but its a start. CSV format. The 4th column is the most interested, and you can simply filter by the aws resources you use, and the CRUD operations you want with a simple grep

Terraform Resources,AWS Resource,CRUD Operation,PolicyRule Required,,,,
aws_network_acl,NetworkAcl,CREATE,ec2:CreateNetworkAcl,1.6.1,,,
aws_network_acl,NetworkAcl,CREATE,ec2:CreateNetworkAclEntry,1.6.1,,,
aws_network_acl,NetworkAcl,READ,ec2:DescribeNetworkAcls,1.6.1,,,
aws_network_acl,NetworkAcl,UPDATE,ec2:ReplaceNetworkAclAssociation,1.6.1,,,
aws_network_acl,NetworkAcl,DELETE,ec2:DeleteNetworkAcl,1.6.1,,,
aws_network_acl,NetworkAcl,DELETE,ec2:DeleteNetworkAclEntry,1.6.1,,,
aws_network_interface,NetworkInterface,CREATE,ec2:CreateNetworkInterface,1.6.1,,,
aws_network_interface,NetworkInterface,CREATE,ec2:AttachNetworkInterface,1.6.1,,,
aws_network_interface,NetworkInterface,READ,ec2:DescribeNetworkInterfaceAttributes,1.6.1,,,
aws_network_interface,NetworkInterface,READ,ec2:DescribeNetworkInterfaces,1.6.1,,,
aws_network_interface,NetworkInterface,UPDATE,ec2:ModifyNetworkInterfaceAttribute,1.6.1,,,
aws_network_interface,NetworkInterface,DELETE,ec2:DetachNetworkInterface,1.6.1,,,
aws_network_interface,NetworkInterface,DELETE,ec2:DeleteNetworkInterface,1.6.1,,,
aws_autoscaling_group,AutoScalingGroup,CREATE,autoscaling:AttachLoadbalancers,1.6.1,,,
aws_autoscaling_group,AutoScalingGroup,CREATE,autoscaling:CreateAutoScalingGroup,1.6.1,,,
aws_autoscaling_group,AutoScalingGroup,READ,autoscaling:DescribeAutoScalingGroups,1.6.1,,,
aws_autoscaling_group,AutoScalingGroup,READ,elasticloadbalancing:DescribeInstanceHealth,1.6.1,,,
aws_autoscaling_group,AutoScalingGroup,UPDATE,autoscaling:UpdateAutoScalingGroup,1.6.1,,,
aws_autoscaling_group,AutoScalingGroup,DELETE,autoscaling:DetachLoadbalancers,1.6.1,,,
aws_autoscaling_group,AutoScalingGroup,DELETE,autoscaling:DeleteAutoScalingGroup,1.6.1,,,
aws_launch_configuration,LaunchConfiguration,CREATE,autoscaling:CreateLaunchConfiguration,1.6.1,,,
aws_launch_configuration,LaunchConfiguration,READ,autoscaling:DescribeLaunchConfiguration,1.6.1,,,
aws_launch_configuration,LaunchConfiguration,DELETE,autoscaling:DeleteLaunchConfiguration,1.6.1,,,
aws_vpc,Vpc,CREATE,ec2:CreateVpc,1.6.1,,,
aws_vpc,Vpc,CREATE,ec2:DescribeNetworkACLs,1.6.1,,,
aws_vpc,Vpc,CREATE,ec2:DescribeRouteTables,1.6.1,,,
aws_vpc,Vpc,READ,ec2:DescribeSecurityGroups,1.6.1,,,
aws_vpc,Vpc,READ,ec2:DescribeVpcAttribute,1.6.1,,,
aws_vpc,Vpc,READ,ec2:DescribeVpc,1.6.1,,,
aws_vpc,Vpc,UPDATE,ec2:ModifyVpcAttribute,1.6.1,,,
aws_vpc,Vpc,DELETE,ec2:DeleteVpc,1.6.1,,,
aws_vpc_endpoint,VpcEndpoint,CREATE,ec2:CreateVpc,1.6.1,,,
aws_vpc_endpoint,VpcEndpoint,CREATE,ec2:CreateVpcEndpoint,1.6.1,,,
aws_vpc_endpoint,VpcEndpoint,READ,ec2:DescribeVpcEndpoints,1.6.1,,,
aws_vpc_endpoint,VpcEndpoint,UPDATE,ec2:ModifyVpcEndpoint,1.6.1,,,
aws_vpc_endpoint,VpcEndpoint,DELETE,ec2:DeleteVpcEndpoints,1.6.1,,,
aws_vpc_endpoint,VpcEndpoint,DELETE,ec2:DeleteVpc,1.6.1,,,
aws_vpc_peering_connection,VpcPeeringConnection,CREATE,ec2:CreateVpc,1.6.1,,,
aws_vpc_peering_connection,VpcPeeringConnection,CREATE,ec2:CreateVpcPeeringConnection,1.6.1,,,
aws_vpc_peering_connection,VpcPeeringConnection,CREATE,ec2:AcceptVpcPeeringConnection,1.6.1,,,
aws_vpc_peering_connection,VpcPeeringConnection,READ,ec2:DescribeVpcPeeringConnections,1.6.1,,,
aws_vpc_peering_connection,VpcPeeringConnection,DELETE,ec2:DeleteVpc,1.6.1,,,
aws_vpc_peering_connection,VpcPeeringConnection,DELETE,ec2:DeleteVpcPeeringConnection,1.6.1,,,
aws_subnet,Subnet,CREATE,ec2:CreateSubnet,1.6.1,,,
aws_subnet,Subnet,READ,ec2:DescribeSubnets,1.6.1,,,
aws_subnet,Subnet,UPDATE,ec2:ModifySubnetAttributes,1.6.1,,,
aws_subnet,Subnet,DELETE,ec2:DeleteSubnet,1.6.1,,,
aws,Tags,CREATE,ec2:CreateTags,1.6.1,,,
aws,Tags,DELETE,ec2:DeleteTags,1.6.1,,,
aws_instance,Instance,CREATE,ec2:RunInstances,1.6.1,,,
aws_instance,Instance,CREATE,ec2:MonitorInstances,1.6.1,,,
aws_instance,Instance,READ,ec2:DescribeImages,1.6.1,,,
aws_instance,Instance,READ,ec2:DescribeVolumes,1.6.1,,,
aws_instance,Instance,READ,ec2:DescribeInstances,1.6.1,,,
aws_instance,Instance,UPDATE,ec2:ModifyInstanceAttribute,1.6.1,,,
aws_instance,Instance,DELETE,ec2:TerminateInstances,1.6.1,,,
aws_instance,Instance,DELETE,ec2:UnmonitorInstances,1.6.1,,,
aws_security_group,SecurityGroup,CREATE,ec2:CreateSecurityGroup,1.6.1,,,
aws_security_group,SecurityGroup,CREATE,ec2:AuthorizeSecurityGroupEgress,1.6.1,,,
aws_security_group,SecurityGroup,CREATE,ec2:AuthorizeSecurityGroupIngress,1.6.1,,,
aws_security_group,SecurityGroup,CREATE,ec2:RevokeSecurityGroupEgress,1.6.1,,,
aws_security_group,SecurityGroup,CREATE,ec2:RevokeSecurityGroupIngress,1.6.1,,,
aws_security_group,SecurityGroup,READ,ec2:DescribeSecurityGroups,1.6.1,,,
aws_security_group,SecurityGroup,DELETE,ec2:RevokeSecurityGroupIngress,1.6.1,,,
aws_security_group,SecurityGroup,DELETE,ec2:RevokeSecurityGroupEgress,1.6.1,,,
aws_security_group,SecurityGroup,DELETE,ec2:DeleteSecurityGroup,1.6.1,,,
aws_security_group_rule,SecurityGroupEgress,CREATE,ec2:AuthorizeSecurityGroupEgress,1.6.1,,,
aws_security_group_rule,SecurityGroupEgress,READ,ec2:DescribeSecurityGroups,1.6.1,,,
aws_security_group_rule,SecurityGroupEgress,DELETE,ec2:RevokeSecurityGroupEgress,1.6.1,,,
aws_security_group_rule,SecurityGroupIngress,CREATE,ec2:AuthorizeSecurityGroupIngress,1.6.1,,,
aws_security_group_rule,SecurityGroupIngress,READ,ec2:DescribeSecurityGroups,1.6.1,,,
aws_security_group_rule,SecurityGroupIngress,DELETE,ec2:RevokeSecurityGroupIngress,1.6.1,,,
aws_internet_gateway,InternetGateway,CREATE,ec2:CreateInternetGateway,1.6.1,,,
aws_internet_gateway,InternetGateway,CREATE,ec2:AttachInternetGateway,1.6.1,,,
aws_internet_gateway,InternetGateway,READ,ec2:DescribeInternetGateways,1.6.1,,,
aws_internet_gateway,InternetGateway,DELETE,ec2:DetachInternetGateway,1.6.1,,,
aws_internet_gateway,InternetGateway,DELETE,ec2:DeleteInternetGateway,1.6.1,,,
aws_route_table,Route,CREATE,ec2:CreateRoute,1.6.1,,,
aws_route_table,Route,DELETE,ec2:DeleteRoute,1.6.1,,,
aws_route_table,RouteTable,CREATE,ec2:CreateRouteTable,1.6.1,,,
aws_route_table,RouteTable,CREATE,ec2:EnableVGWRoutePropagation,1.6.1,,,
aws_route_table,RouteTable,READ,ec2:DescribeRouteTable,1.6.1,,,
aws_route_table,RouteTable,DELETE,ec2:DisableVGWRoutePropagation,1.6.1,,,
aws_route_table,RouteTable,DELETE,ec2:DisassociateRouteTable,1.6.1,,,
aws_route_table,RouteTable,DELETE,ec2:DeleteRouteTable,1.6.1,,,
aws_eip,Address,CREATE,ec2:AllocateAddress,1.6.1,,,
aws_eip,Address,CREATE,ec2:AssociateAddress,1.6.1,,,
aws_eip,Address,READ,ec2:DescribeAddresses,1.6.1,,,
aws_eip,Address,DELETE,ec2:ReleaseAddress,1.6.1,,,
aws_eip,Address,DELETE,ec2:DisassociateAddress,1.6.1,,,
aws_main_route_table_association,RouteTable,READ,ec2:DescribeRouteTable,1.6.1,,,
aws_main_route_table_association,RouteTable,UPDATE,ec2:ReplaceRouteTableAssociation,1.6.1,,,
aws_route_table_association,RouteTable,CREATE,ec2:AssociateRouteTable,1.6.1,,,
aws_route_table_association,RouteTable,UPDATE,ec2:ReplaceRouteTableAssociation,1.6.1,,,
aws_route_table_association,RouteTable,DELETE,ec2:DisassociateRouteTable,1.6.1,,,
aws_route_53_record,Route53Record,UPDATE,route53:ChangeResourceRecordSets,1.6.1,,,
aws_route_53_record,Route53Record,READ,route53:GetHostedZone,1.6.1,,,
aws_route_53_record,Route53Record,READ,route53:ListResourceRecordSets,1.6.1,,,
aws_route_53_record,Route53Record,UPDATE,route53:ChangeTagsForResource,1.6.1,,,
aws_reoute_53_health_check,Route53HealthCheck,CREATE,route53:CreateHealthCheck,1.6.1,,,
aws_reoute_53_health_check,Route53HealthCheck,READ,route53:GetHealthCheck,1.6.1,,,
aws_reoute_53_health_check,Route53HealthCheck,READ,route53:ListTagsForResource,1.6.1,,,
aws_reoute_53_health_check,Route53HealthCheck,UPDATE,route53:UpdateHealthCheck,1.6.1,,,
aws_reoute_53_health_check,Route53HealthCheck,DELETE,route53:DeleteHealthCheck,1.6.1,,,
aws_ebs_volume,Volume,CREATE,ec2:CreateVolume,1.6.1,,,
aws_ebs_volume,Volume,DELETE,ec2:DeleteVolume,1.6.1,,,
aws_ebs_volume,Volume,READ,ec2:DescribeVolumes,1.6.1,,,
aws_volume_attachment,Volume,CREATE,ec2:AttachVolume,1.6.1,,,
aws_volume_attachment,Volume,READ,ec2:DescribeVolumes,1.6.1,,,
aws_volume_attachment,Volume,DELETE,ec2:DetachVolume,1.6.1,,,
aws_elb,ElasticLoadBalancer,CREATE,elasticloadbalancing:ApplySecurityGroupsToLoadbalancer,1.6.1,,,
aws_elb,ElasticLoadBalancer,CREATE,elasticloadbalancing:ConfigureHealthCheck,1.6.1,,,
aws_elb,ElasticLoadBalancer,CREATE,elasticloadbalancing:CreateLoadBalancer,1.6.1,,,
aws_elb,ElasticLoadBalancer,CREATE,elasticloadbalancing:CreateLoadBalancerListeners,1.6.1,,,
aws_elb,ElasticLoadBalancer,CREATE,elasticloadbalancing:RegisterInstancesWithLoadBalancer,1.6.1,,,
aws_elb,ElasticLoadBalancer,CREATE,elasticloadbalancing:AddTags,1.6.1,,,
aws_elb,ElasticLoadBalancer,READ,elasticloadbalancing:DescribeLoadBalancerAttributes,1.6.1,,,
aws_elb,ElasticLoadBalancer,READ,elasticloadbalancing:DescribeLoadBalancers,1.6.1,,,
aws_elb,ElasticLoadBalancer,READ,elasticloadbalancing:DescribeTags,1.6.1,,,
aws_elb,ElasticLoadBalancer,UPDATE,elasticloadbalancing:ModifyLoadBalancerAttributes,1.6.1,,,
aws_elb,ElasticLoadBalancer,DELETE,elasticloadbalancing:DeleteLoadBalancer,1.6.1,,,
aws_elb,ElasticLoadBalancer,DELETE,elasticloadbalancing:DeleteLoadBalancerListeners,1.6.1,,,
aws_elb,ElasticLoadBalancer,DELETE,elasticloadbalancing:DeregisterInstancesFromLoadBalancer,1.6.1,,,
aws_elb,ElasticLoadBalancer,DELETE,elasticloadbalancing:RemoveTags,1.6.1,,,
aws_iam_instance_profile,IamInstanceProfile,CREATE,iam:AddRoleToInstanceProfile,1.6.1,,,
aws_iam_instance_profile,IamInstanceProfile,CREATE,iam:CreateInstanceProfile,1.6.1,,,
aws_iam_instance_profile,IamInstanceProfile,READ,iam:GetInstanceProfile,1.6.1,,,
aws_iam_instance_profile,IamInstanceProfile,DELETE,iam:DeleteInstanceProfile,1.6.1,,,
aws_iam_instance_profile,IamInstanceProfile,DELETE,iam:RemoveRoleFromInstanceProfile,1.6.1,,,

@lkraider
Copy link

Please provide this as part of the docs/repo so that policy can be generated as needed.

@blalor
Copy link
Contributor

blalor commented Jan 29, 2016

That's pretty excellent @gtmtech. Would really like to see official support for this.

@blalor
Copy link
Contributor

blalor commented Jan 29, 2016

oh, neat. AWS has a maximum policy size limit of 2k. so if you've got an even moderately-sized terraform config for AWS you've basically gotta just wildcard everything. :-(

@steve-jansen
Copy link
Contributor

@blalor my IAM skills aren't very sharp... anyways, perhaps you can use a short Deny to allow TF to do most things but deny deletes?

2016-01-29_12-15-08
Source: AWS re:Invent 2015 (SEC305) - How to Become an IAM Policy Ninja in 60 Minutes or Less

*edit: corrected myself after not reading far enough ahead.. d'oh

@blalor
Copy link
Contributor

blalor commented Jan 30, 2016 via email

@blalor
Copy link
Contributor

blalor commented Jan 30, 2016

@blalor
Copy link
Contributor

blalor commented Jan 31, 2016

So, reading through that, policy documents can be bigger, depending on how they're used (ie policies attached to users are limited to 2k, but managed policies are I think 5k). I'm using Vault's AWS secret backend to create a user with the required permissions to apply Terraform configs, and that doesn't currently seem to support managed policies.

Anyway:
the more you know

@anshulp25
Copy link

Hi Guys,

Was able to launch instance with the following policy.

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:DescribeInstances", "ec2:DescribeImages", "ec2:DescribeKeyPairs", "ec2:DescribeSecurityGroups", "ec2:DescribeAvailabilityZones", "ec2:RunInstances", "ec2:TerminateInstances", "ec2:StopInstances", "ec2:StartInstances", "ec2:MonitorInstances", "ec2:DescribeVolumes", "ec2:ModifyInstanceAttribute", "ec2:UnmonitorInstances" ], "Resource": [ "arn:aws:ec2:<region>::instance/*" ], "Condition": { "StringEquals": { "ec2:InstanceType": [ "t2.micro" ] } } } ] }

@lkraider
Copy link

lkraider commented Apr 4, 2016

Here is a script to convert the CSV policies list as extracted by @gtmtech into AWS JSON format: https://gist.github.com/lkraider/65fae06e8b71ef593c403db2e9f7f7bf

@aarcro
Copy link

aarcro commented May 26, 2016

I was able to generate the JSON policies, but they are too big to use :(
How does anyone actually use terraform on AWS? Even my root keys are getting 403'd for something.

@deluxebrain
Copy link

deluxebrain commented Jun 28, 2016

@gtmtech Thanks so much for the csv export.

Incase anyone else needs a quick and easy way to process it, I'm using the wonderful csvkit`` andjq```` to generate json arrays of policy rules from the csv.

E.g. the following will generate a json array of all CREATE rules:

csvgrep -c 3 -r "^CREATE" policies.csv | csvcut -c 4 | sort -u  | csvjson | jq '{Action: [.[] | .["PolicyRule Required"]]}'

@artburkart
Copy link
Contributor

The way I approached this problem was by creating an instance with terraform using a policy that was too lenient. Then, I checked the affected resources logged through CloudTrail. The result was a policy that looked like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ec2:RunInstances",
                "ec2:StartInstances"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:ec2:::instance/*",
                "arn:aws:ec2:::network-interface/eni-hexadeci",
                "arn:aws:ec2:::subnet/subnet-hexadeci",
                "arn:aws:ec2:::security-group/sg-hexadeci",
                "arn:aws:ec2:::key-pair/name_of_key",
                "arn:aws:ec2:region::image/ami-hexadeci"
            ]
        },
        {
            "Action": [
                "ec2:Describe*",
                "ec2:CreateTags",
                "ec2:CreateVolume",
                "ec2:RegisterImage",
                "ec2:CreateImage",
                "ec2:CopyImage",
                "ec2:CreateSnapshot",
                "ec2:DeleteSnapshot",
                "ec2:DetachVolume",
                "ec2:ModifyImageAttribute"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": [
                "ec2:StopInstances",
                "ec2:TerminateInstances"
            ],
            "Condition": {
                "StringEquals": {
                    "ec2:ResourceTag/provisioned_by": "ci"
                }
            },
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": [
                "ec2:StopInstances",
                "ec2:TerminateInstances"
            ],
            "Condition": {
                "StringLike": {
                    "ec2:ResourceTag/environment": [
                        "prod",
                        "qa",
                        "stage",
                        "automation"
                    ]
                }
            },
            "Effect": "Deny",
            "Resource": "*"
        }
    ]
}

Since CreateTags does not have resource-level permissions available to it, I say that if an instance has certain values for the environment tag on it, then the user of the above policy is not allowed to terminate or stop that instance. This way the user of the above policy can add whatever tags it wants wherever, but it can't be destructive. The second statement object beginning with ec2:Describe* is not restricted to any resource because it can't be.

@gtmtech
Copy link
Author

gtmtech commented Aug 4, 2016

There are some great suggestions here, although they are very limited in scope (e.g. just spinning up an instance). I still think there's mileage in generating a role specific to the resources you are actually using, with a higher level terraform command. (or jq wizardry as above)

To the commenter above, you can have multiple policies attached to a role (when you run out of space), so this wasnt a problem for us. (You can ask AWS about this).

In the end, we did enough to have some level of confidence that if the role got into the wrong hands, people still aren't going to be able to delete some of the critical infrastructure in production, and accompanied with terraform's own lifecycle prevent_destroy, and other backup/DR options, thats at least 3 levels of protection. I'd like to see some fundamental terraform support for the generation of an iam role - just as there is a well documented one in packer.

@apparentlymart
Copy link
Member

It seems like this sort of thing would necessarily be provider-specific rather than something Terraform could handle generically, so I think I'd be inclined to try to model this as a data source in the AWS provider:

data "aws_terraform_resource_policy" "example" {
  resources = ["aws_elb", "aws_instance", "aws_security_group"]
}
resource "aws_iam_policy" "example" {
  # ...
  policy = "${data.aws_terraform_resource_policy.example.json}"
}

My idea here is that the data source produces a JSON policy that has enough access to CRUD the resource types listed.

This is not a complete solution as-specified, though. For example, I expect it would be pretty common to want to constrain the access to subsets of the given resources... for example, to create resources only within a particular VPC. Perhaps the logical conclusion of this is just an extra attribute on the existing aws_iam_policy_document data source that adds additional Action values to the generated policy.

@arsdehnel
Copy link
Contributor

Just came across this today, thanks for the great list @gtmtech. I took that and created some IAM Policy Document resources from them as a starting point for myself (and others). Seems like it's doing what we need although I'm sure there always going to be adjustments and new resources to be added.

Here are my 4 policies if anyone else wants to use them: https://gist.github.com/arsdehnel/70e292467ced2a39f472ddca44629c08

By posting these I take no legal responsibility whatsoever if they have some security loophole in them that allows someone to take down your entire infrastructure. They're just a starting point :)

@arsdehnel
Copy link
Contributor

Also wanted to note that I got that same error @gilesbutler and adding the iam:PassRole to the actions array in my "create" policy seems to have resolved that issue.

@richarddowner
Copy link

Hi all thanks for your efforts so far, It would be really good if we could get a list of policy actions that each terraform resource needs to execute. For example: something like this:

aws_security_groups
"ec2:CreateSecurityGroup",
"ec2:AuthorizeSecurityGroupEgress",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupEgress",
"ec2:RevokeSecurityGroupIngress",
"ec2:DescribeSecurityGroups",
"ec2:DeleteSecurityGroup"

How can I determine what each resource needs? Thanks

@artburkart
Copy link
Contributor

@richardbowden Is the policy I shared not sufficient? It was the bare minimum permissions required for it to work.

@xenoterracide
Copy link

xenoterracide commented Mar 12, 2017

might it be possible to have terraform print the privileges it needs for the actions it' trying to complete when it fails? I would think you could make a map for each attempted change to a privilege.

@arsdehnel
Copy link
Contributor

Only if the AWS API responds with it. Sometimes it does and sometimes it doesn't. TF won't inherently know what it needs, that's an AWS thing.

@xenoterracide
Copy link

:/ I was thinking since TF is designing itself to manage these things presumably it could maintain a map of privileges required... per resource maintained... although I can see that getting ridiculous fast

@copumpkin
Copy link

copumpkin commented Mar 12, 2017 via email

@xenoterracide
Copy link

heck, even just emitting the last api called would be helpful, probably has had 80% of what I needed to figure out which permission failed, and then a ton of other less useful information. If it said Id just called s3/GetBucketLogging on error... well I bet there's a perm that corresponds to that.

2017/03/12 06:51:06 [DEBUG] plugin: terraform: aws-provider (internal) 2017/03/12 06:51:06 [DEBUG] [aws-sdk-go] DEBUG: Response s3/GetBucketLogging Details:

@apparentlymart
Copy link
Member

Hi everyone!

Thanks to @gtmtech for introducing this request and to everyone else for the great discussion on it in the mean time.

After spending some time thinking about this, we've concluded that this is a non-trivial problem to solve due to the many and varied capabililties of IAM across all of the AWS services and the difficulty of predicting the right granularity for a policy.

Therefore we (the Terraform team) are not planning to move forward with any specific feature in this area, and instead suggest that people should refer to the AWS documentation to get the full details about the various possibilities for granting access to each AWS action.

However, we know that right now it's often hard to determine from the Terraform documentation exactly what actions are being executed for a given resource, and thus know how to map what's in the AWS documentation. In future we'd like to add additional information to the documentation for various resources to be a bit more explicit about what actions are being executed, though that is a big project and not something that's going to happen against a single, broad issue like this one.

So with all of that said, I'm going to close this issue as part of our effort to prune issues that don't have a clear short-term action plan. If there are resources with particularly-hairy policy requirements we would be happy to review small PRs to update the relevant documentation.

@dhoffi
Copy link

dhoffi commented Dec 15, 2017

being a total newbie maybe I miss the point.
For me it succeeded with the following two roles ... but they definitely may not be "minimal"

AmazonEC2FullAccess
AmazonSSMFullAccess

@tdmalone
Copy link

@dhoffi That definitely works, but the point is to give the minimal access required, so as to limit the damage that can be caused if you accidentally apply something you didn't intend to (or worse, if someone else gets a hold of the access keys). * also works... but that's even worse ;)

@bitdivine
Copy link

bitdivine commented Jan 4, 2019

@gtmtech Love the list. If you put it on github somewhere we can crowd source the remaining entries. As you started the list, would you like to do the honours? If you are too busy I would be happy to.

I would b every interested in being able to extract the resources programmatically as well but that is one step further. Walking would be a good start.

@Zeal0us
Copy link

Zeal0us commented Feb 6, 2019

It really seems like it should be able to parse a script and spit out an IAM policy (or Role) that define what exactly it needs, essentially doing a dry run against possible states (Might recreate the resource, change it, or make one from scratch, etc...). The concern isn't even necessarily terraform so much as giving the credentials using terraform power they don't need.

@jralmaraz
Copy link

Thanks! That helped a lot.

I still got an authorized when creating VPC even though I got AmazonEC2FullAccess , AmazonSSMFullAccess , AmazonVPCFullAccess.

  • aws_vpc.ifacade: Error creating VPC: UnauthorizedOperation: You are not authorized to perform this operation.

@c0nfleis
Copy link

Thanks! That helped a lot.

I still got an authorized when creating VPC even though I got AmazonEC2FullAccess , AmazonSSMFullAccess , AmazonVPCFullAccess.

  • aws_vpc.ifacade: Error creating VPC: UnauthorizedOperation: You are not authorized to perform this operation.

You probably want to triple check that you dont have an explicit deny of some sort somewhere in your Terraform.

@ghost
Copy link

ghost commented Aug 13, 2019

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Aug 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests