├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── bootstrap ├── locals.tf ├── policies │ ├── assume_roles │ │ ├── terraform_aws_permissions_generator_permissions_add_role.json.tpl │ │ └── terraform_aws_permissions_generator_role.json.tpl │ ├── terraform_aws_permissions_generator_permissions_add_policy.json.tpl │ └── user_policy.json.tpl ├── provider.tf ├── roles.tf ├── templates │ ├── aws_config.tpl │ └── aws_credentials.tpl ├── user.tf └── variables.tf ├── completed_policies └── .placeholder ├── generate ├── lib ├── generate.rb └── generate │ ├── errors.rb │ ├── generator.rb │ ├── helper.rb │ ├── log_parser.rb │ ├── logger.rb │ ├── policy_generator.rb │ └── terraform.rb ├── policy_modifier ├── locals.tf ├── policy.tf ├── provider.tf └── variables.tf └── test_resources ├── ec2_instance.tf ├── provider.tf └── variables.tf /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # .tfvars files 9 | *.tfvars 10 | 11 | # vendor directory 12 | /vendor/ 13 | 14 | # terraform state S3 15 | bootstrap/terraform_state_s3.tf 16 | 17 | # generated credentials 18 | terraform_aws_permissions_generator_user_credentials 19 | 20 | # generated config 21 | terraform_aws_permissions_generator_config 22 | 23 | # generated required IAM permissions 24 | required_permissions.json 25 | 26 | # crash log 27 | crash.log 28 | 29 | # completed policies 30 | completed_policies/* 31 | 32 | # dont ignore placeholders 33 | !.placeholder 34 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | gem 'colorize' 2 | gem 'json' 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform AWS Permissions Generator 2 | 3 | **Warning:** This will launch and destroy all resources defined within your terraform project. 4 | I'd recommend creating a new AWS account to run this. 5 | 6 | Terraform AWS Permissions Generator creates an AWS IAM policy containing only the permissions required to launch and destroy resources defined in a terraform project. 7 | 8 | It does this by running terraform, then parsing the crash log for the permissions it needs, adding them to a policy, and trying again until terraform completes successfully. 9 | 10 | **Disclaimer:** This was just a bit of weekend fun - There's probably much better ways to get a set of permissions. Use at your own risk! 11 | 12 | ## Quick Start 13 | 14 | The AWS account you will be running this against will need bootstrapping to create the required user/roles/policies to allow the generator to run. 15 | 16 | To bootstrap the account: 17 | 18 | ``` 19 | cd bootstrap 20 | terraform init 21 | terraform apply -var region= 22 | ``` 23 | 24 | This also places the user credentials and config in the following files, at the root of this repo: 25 | 26 | ``` 27 | terraform_aws_permissions_generator_config 28 | terraform_aws_permissions_generator_user_credentials 29 | ``` 30 | 31 | They need to be there to run the generate script 32 | 33 | Some directories in the project need to be initialized, and dependencies installed. You may add terraform backends if you wish. To setup: 34 | 35 | ``` 36 | bundle install 37 | cd policy_modifier 38 | terraform init 39 | cd .. 40 | cd test_resources 41 | terraform init 42 | cd .. 43 | ``` 44 | 45 | You can now run the generate script. This is the point that resources will begin being created and destroyed. 46 | 47 | Using `test_resources` as an example, which launches and destroys a `t2.micro` EC2 instance: 48 | 49 | ``` 50 | ./generate --region --terraform-path test_resources 51 | ``` 52 | 53 | Once complete, it will output an IAM policy into `completed_policies` 54 | 55 | ## Usage 56 | 57 | ``` 58 | Usage: generate [options] 59 | -v TERRAFORM_VAR_FILE, Terraform variable file 60 | --var-file 61 | -r, --region AWS_REGION AWS Region 62 | -p TERRAFORM_PATH, Terraform path 63 | --terraform-path 64 | -a, --auto-approve AUTO_APPROVE Auto approve 65 | ``` 66 | -------------------------------------------------------------------------------- /bootstrap/locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | account_id = "${data.aws_caller_identity.current.account_id}" 3 | } 4 | -------------------------------------------------------------------------------- /bootstrap/policies/assume_roles/terraform_aws_permissions_generator_permissions_add_role.json.tpl: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "AWS": [ 8 | "${user_arn}" 9 | ] 10 | }, 11 | "Action": "sts:AssumeRole" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /bootstrap/policies/assume_roles/terraform_aws_permissions_generator_role.json.tpl: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "AWS": [ 8 | "${user_arn}" 9 | ] 10 | }, 11 | "Action": "sts:AssumeRole" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /bootstrap/policies/terraform_aws_permissions_generator_permissions_add_policy.json.tpl: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "iam:AttachRolePolicy", 8 | "iam:DetachRolePolicy", 9 | "iam:GetRole", 10 | "iam:ListAttachedRolePolicies" 11 | ], 12 | "Resource": "${terraform_aws_permissions_generator_role_arn}" 13 | }, 14 | { 15 | "Effect": "Allow", 16 | "Action": [ 17 | "iam:CreatePolicy", 18 | "iam:CreatePolicyVersion", 19 | "iam:DeletePolicy", 20 | "iam:DeletePolicyVersion", 21 | "iam:GetPolicy", 22 | "iam:GetPolicyVersion", 23 | "iam:ListPolicyVersions" 24 | ], 25 | "Resource": "${terraform_aws_permissions_generator_policy_arn}" 26 | }, 27 | { 28 | "Effect": "Allow", 29 | "Action": [ 30 | "ec2:DescribeAccountAttributes" 31 | ], 32 | "Resource": "*" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /bootstrap/policies/user_policy.json.tpl: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "ec2:DescribeAccountAttributes" 8 | ], 9 | "Resource": "*" 10 | }, 11 | { 12 | "Effect": "Allow", 13 | "Action": "sts:AssumeRole", 14 | "Resource": "${terraform_aws_permissions_generator_permissions_add_role_arn}" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /bootstrap/provider.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "${var.region}" 3 | } 4 | 5 | data "aws_caller_identity" "current" { 6 | provider = "aws" 7 | } 8 | -------------------------------------------------------------------------------- /bootstrap/roles.tf: -------------------------------------------------------------------------------- 1 | # Role to add polcy containing on the fly permissions that the 2 | # terraform_aws_permissions_generator user can assume 3 | data "template_file" "terraform_aws_permissions_generator_role" { 4 | template = "${file("./policies/assume_roles/terraform_aws_permissions_generator_role.json.tpl")}" 5 | 6 | vars { 7 | user_arn = "${aws_iam_user.terraform_aws_permissions_generator.arn}" 8 | } 9 | } 10 | 11 | resource "aws_iam_role" "terraform_aws_permissions_generator_role" { 12 | name = "terraform_aws_permissions_generator_role" 13 | assume_role_policy = "${data.template_file.terraform_aws_permissions_generator_role.rendered}" 14 | } 15 | 16 | # Role / polciy to allow terraform_aws_permissions_generator to add permissions 17 | # to terraform_aws_permissions_generator_role 18 | data "template_file" "terraform_aws_permissions_generator_permissions_add_role" { 19 | template = "${file("./policies/assume_roles/terraform_aws_permissions_generator_permissions_add_role.json.tpl")}" 20 | 21 | vars { 22 | user_arn = "${aws_iam_user.terraform_aws_permissions_generator.arn}" 23 | } 24 | } 25 | 26 | resource "aws_iam_role" "terraform_aws_permissions_generator_permissions_add_role" { 27 | name = "terraform_aws_permissions_generator_permissions_add_role" 28 | assume_role_policy = "${data.template_file.terraform_aws_permissions_generator_permissions_add_role.rendered}" 29 | } 30 | 31 | data "template_file" "terraform_aws_permissions_generator_permissions_add_policy" { 32 | template = "${file("./policies/terraform_aws_permissions_generator_permissions_add_policy.json.tpl")}" 33 | 34 | vars { 35 | terraform_aws_permissions_generator_role_arn = "${aws_iam_role.terraform_aws_permissions_generator_role.arn}" 36 | terraform_aws_permissions_generator_policy_arn = "arn:aws:iam::${local.account_id}:policy/terraform_aws_permissions_generator_permissions_policy" 37 | } 38 | } 39 | 40 | resource "aws_iam_role_policy" "terraform_aws_permissions_generator_permissions_add_policy" { 41 | name = "terraform_aws_permissions_generator_permissions_add_policy" 42 | role = "${aws_iam_role.terraform_aws_permissions_generator_permissions_add_role.id}" 43 | policy = "${data.template_file.terraform_aws_permissions_generator_permissions_add_policy.rendered}" 44 | } 45 | -------------------------------------------------------------------------------- /bootstrap/templates/aws_config.tpl: -------------------------------------------------------------------------------- 1 | [default] 2 | region=eu-west-2 3 | 4 | [profile generatedpermissions] 5 | source_profile = default 6 | role_arn = ${terraform_aws_permissions_generator_role_arn} 7 | -------------------------------------------------------------------------------- /bootstrap/templates/aws_credentials.tpl: -------------------------------------------------------------------------------- 1 | [default] 2 | aws_access_key_id=${aws_access_key_id} 3 | aws_secret_access_key=${aws_secret_access_key} 4 | -------------------------------------------------------------------------------- /bootstrap/user.tf: -------------------------------------------------------------------------------- 1 | # Create user 2 | resource "aws_iam_user" "terraform_aws_permissions_generator" { 3 | name = "${var.user_name}" 4 | } 5 | 6 | # Create user policy 7 | # Needed to run some terraform actions before assuming role 8 | data "template_file" "user_policy" { 9 | template = "${file("./policies/user_policy.json.tpl")}" 10 | 11 | vars { 12 | terraform_aws_permissions_generator_permissions_add_role_arn = "${aws_iam_role.terraform_aws_permissions_generator_permissions_add_role.arn}" 13 | } 14 | } 15 | 16 | resource "aws_iam_user_policy" "terraform_aws_permissions_generator" { 17 | name = "terraform_aws_permissions_generator" 18 | user = "${aws_iam_user.terraform_aws_permissions_generator.name}" 19 | policy = "${data.template_file.user_policy.rendered}" 20 | } 21 | 22 | # Create access key 23 | resource "aws_iam_access_key" "terraform_aws_permissions_generator" { 24 | user = "${aws_iam_user.terraform_aws_permissions_generator.name}" 25 | } 26 | 27 | # Store credentials 28 | data "template_file" "user_credentials" { 29 | template = "${file("./templates/aws_credentials.tpl")}" 30 | 31 | vars { 32 | aws_access_key_id = "${aws_iam_access_key.terraform_aws_permissions_generator.id}" 33 | aws_secret_access_key = "${aws_iam_access_key.terraform_aws_permissions_generator.secret}" 34 | } 35 | } 36 | 37 | data "template_file" "config" { 38 | template = "${file("./templates/aws_config.tpl")}" 39 | 40 | vars { 41 | terraform_aws_permissions_generator_role_arn = "${aws_iam_role.terraform_aws_permissions_generator_role.arn}" 42 | } 43 | } 44 | 45 | resource "local_file" "credentials" { 46 | content = "${data.template_file.user_credentials.rendered}" 47 | filename = "../terraform_aws_permissions_generator_user_credentials" 48 | 49 | provisioner "local-exec" { 50 | command = "chmod 400 ../terraform_aws_permissions_generator_user_credentials" 51 | } 52 | } 53 | 54 | resource "local_file" "config" { 55 | content = "${data.template_file.config.rendered}" 56 | filename = "../terraform_aws_permissions_generator_config" 57 | 58 | provisioner "local-exec" { 59 | command = "chmod 400 ../terraform_aws_permissions_generator_config" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /bootstrap/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | description = "AWS Region" 3 | type = "string" 4 | } 5 | 6 | variable "user_name" { 7 | description = "Name of AWS user to create" 8 | default = "terraform_aws_permissions_generator" 9 | type = "string" 10 | } 11 | -------------------------------------------------------------------------------- /completed_policies/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Stretch96/terraform-aws-permissions-generator/da620dc2ef821e38f21efc19f20792af5df27c95/completed_policies/.placeholder -------------------------------------------------------------------------------- /generate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | APP_ROOT = File.expand_path(File.dirname(__FILE__)) 4 | 5 | require "#{APP_ROOT}/lib/generate.rb" 6 | require "optparse" 7 | 8 | options = {} 9 | OptionParser.new do |opts| 10 | opts.banner = "Usage: generate [options]" 11 | 12 | opts.on('-v', '--var-file TERRAFORM_VAR_FILE', 'Terraform variable file') { |v| options[:var_File] = v } 13 | opts.on('-r', '--region AWS_REGION', 'AWS Region') { |v| options[:region] = v } 14 | opts.on('-p', '--terraform-path TERRAFORM_PATH', 'Terraform path') { |v| options[:terraform_path] = v } 15 | opts.on('-a', '--auto-approve AUTO_APPROVE', 'Auto approve') { |v| options[:auto_approve] = v } 16 | end.parse! 17 | 18 | tfvars = { 19 | 'region' => options[:region] 20 | } 21 | 22 | terraform_path = File.expand_path(options[:terraform_path]) 23 | 24 | auto_approve = if options[:auto_approve] == 'true' 25 | true 26 | else 27 | false 28 | end 29 | 30 | Generate::Generator.run( 31 | terraform_path, 32 | tfvars: tfvars, 33 | log_file: "#{APP_ROOT}/crash.log", 34 | credentials: "#{APP_ROOT}/terraform_aws_permissions_generator_user_credentials", 35 | config: "#{APP_ROOT}/terraform_aws_permissions_generator_config", 36 | auto_approve: auto_approve, 37 | policy_path: "#{APP_ROOT}/required_permissions.json", 38 | policy_modifier_path: "#{APP_ROOT}/policy_modifier", 39 | completed_policies_dir: "#{APP_ROOT}/completed_policies", 40 | ) 41 | -------------------------------------------------------------------------------- /lib/generate.rb: -------------------------------------------------------------------------------- 1 | require_relative "generate/helper" 2 | require_relative "generate/terraform" 3 | require_relative "generate/errors" 4 | require_relative "generate/logger" 5 | require_relative "generate/log_parser" 6 | require_relative "generate/policy_generator" 7 | require_relative "generate/generator" 8 | -------------------------------------------------------------------------------- /lib/generate/errors.rb: -------------------------------------------------------------------------------- 1 | module Generate 2 | class Error < RuntimeError; end 3 | end 4 | -------------------------------------------------------------------------------- /lib/generate/generator.rb: -------------------------------------------------------------------------------- 1 | module Generate 2 | class Generator 3 | require "fileutils" 4 | require "date" 5 | def self.run( 6 | terraform_path, 7 | var_file: "", 8 | tfvars: {}, 9 | auto_approve: true, 10 | log_file: 'crash.log', 11 | credentials: 'terraform_aws_permissions_generator_user_credentials', 12 | config: 'terraform_aws_permissions_generator_config', 13 | policy_path: 'required_permissions.json', 14 | policy_modifier_path: 'policy_modifier', 15 | finished_apply: false, 16 | completed_policies_dir: 'completed_policies' 17 | ) 18 | clean_up(crash_log: log_file) 19 | Dir.chdir terraform_path do 20 | Terraform.maybe_create_workspace('terraform-aws-permissions-generator') 21 | begin 22 | if !finished_apply 23 | Logger.info('Running terraform apply ...') 24 | Terraform.apply_with_log( 25 | var_file: var_file, 26 | tfvars: tfvars, 27 | auto_approve: auto_approve, 28 | log_file: log_file, 29 | credentials: credentials, 30 | config: config, 31 | profile: 'generatedpermissions' 32 | ) 33 | end 34 | finished_apply = true 35 | Logger.info('Running terraform destroy ...') 36 | Terraform.destroy_with_log( 37 | var_file: var_file, 38 | tfvars: tfvars, 39 | auto_approve: auto_approve, 40 | log_file: log_file, 41 | credentials: credentials, 42 | config: config, 43 | profile: 'generatedpermissions' 44 | ) 45 | Dir.chdir policy_modifier_path do 46 | Logger.info('Destroying policy in AWS ...') 47 | Terraform.destroy_with_log( 48 | var_file: var_file, 49 | tfvars: tfvars, 50 | auto_approve: auto_approve, 51 | log_file: log_file, 52 | credentials: credentials 53 | ) 54 | end 55 | completed_policy_path = move_required_permissions_to_dir(policy_path, dir: completed_policies_dir) 56 | clean_up(crash_log: log_file) 57 | Logger.success("All done :D") 58 | Logger.success("Policy stored at:") 59 | Logger.success(" #{completed_policy_path}") 60 | return 61 | rescue Error 62 | Logger.info('Finding permission in crash log ...') 63 | permissions = LogParser.get_permission_values(log_file: log_file) 64 | if !permissions.any? 65 | Logger.warn('No permissions found in log. Terraform may have errored due to reasons other than lack of permissions.') 66 | clean_up(crash_log: log_file) 67 | return 68 | end 69 | permissions.each do |permission| 70 | Logger.info("Adding #{permission} to policy") 71 | PolicyGenerator.add_permission(permission_string: permission, path: policy_path) 72 | end 73 | Logger.info("Updating policy ...") 74 | Dir.chdir policy_modifier_path do 75 | Terraform.apply_with_log( 76 | var_file: var_file, 77 | tfvars: tfvars, 78 | auto_approve: auto_approve, 79 | log_file: log_file, 80 | credentials: credentials 81 | ) 82 | end 83 | Logger.info("Policy updated, waiting 5 seconds before continuing ...") 84 | sleep(5) 85 | run( 86 | terraform_path, 87 | var_file: var_file, 88 | tfvars: tfvars, 89 | auto_approve: auto_approve, 90 | log_file: log_file, 91 | credentials: credentials, 92 | config: config, 93 | policy_path: policy_path, 94 | policy_modifier_path: policy_modifier_path, 95 | finished_apply: finished_apply, 96 | completed_policies_dir: completed_policies_dir 97 | ) 98 | end 99 | end 100 | end 101 | 102 | def self.clean_up(crash_log: 'crash.log') 103 | if File.exist?(crash_log) 104 | Logger.info("Deleting crash log ...") 105 | File.delete(crash_log) 106 | end 107 | end 108 | 109 | def self.move_required_permissions_to_dir(policy_path, dir: 'completed_policies') 110 | datetime = DateTime.now 111 | dt = datetime.strftime("%Y%m%d%H%M%S") 112 | new_filename = "#{dt}.json" 113 | FileUtils.mv(policy_path, "#{dir}/#{new_filename}") 114 | return "#{dir}/#{new_filename}" 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/generate/helper.rb: -------------------------------------------------------------------------------- 1 | module Generate 2 | class Helper 3 | def self.run!(command) 4 | Kernel.system(command) || 5 | raise(Error, "'#{command}' failed with exit code #{$CHILD_STATUS}") 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/generate/log_parser.rb: -------------------------------------------------------------------------------- 1 | module Generate 2 | class LogParser 3 | def self.search_string 4 | 'Validate Response' 5 | end 6 | 7 | def self.get_lines(log_file: 'crash.log') 8 | lines = [] 9 | file = File.open(log_file, 'r') 10 | file.each_line do |line| 11 | if line.match(search_string) 12 | lines << line 13 | end 14 | end 15 | lines 16 | end 17 | 18 | def self.get_permission_values(log_file: 'crash.log') 19 | lines = get_lines(log_file: log_file) 20 | permissions = [] 21 | lines.each do |line| 22 | line_words = line.split(/[\s\:]/) 23 | permissions << line_words[line_words.find_index('Response') + 1].gsub('/',':') 24 | end 25 | permissions 26 | end 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/generate/logger.rb: -------------------------------------------------------------------------------- 1 | module Generate 2 | class Logger 3 | require 'colorize' 4 | 5 | def self.error(message) 6 | raise("[!] #{message}".colorize(:light_red)) 7 | end 8 | 9 | def self.info(message) 10 | Kernel.puts "[*] #{message}".colorize(:light_white) 11 | end 12 | 13 | def self.success(message) 14 | Kernel.puts "[*] #{message}".colorize(:light_green) 15 | end 16 | 17 | def self.warn(message) 18 | Kernel.puts "[*] #{message}".colorize(:light_yellow) 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/generate/policy_generator.rb: -------------------------------------------------------------------------------- 1 | module Generate 2 | class PolicyGenerator 3 | require 'json' 4 | 5 | def self.policy_file_path 6 | 'required_permissions.json' 7 | end 8 | 9 | def self.load_policy(path: policy_file_path) 10 | if File.exist?(path) 11 | policy = JSON.parse(File.read(path)) 12 | else 13 | policy = { 14 | "Version" => "2012-10-17", 15 | "Statement" => [ 16 | { 17 | "Effect" => "Allow", 18 | "Action" => [], 19 | "Resource" => "*" 20 | } 21 | ] 22 | } 23 | save_policy(policy: policy) 24 | end 25 | policy 26 | end 27 | 28 | def self.save_policy(policy:,path: policy_file_path) 29 | File.open(path,"w") do |f| 30 | f.write(JSON.pretty_generate(policy)) 31 | end 32 | end 33 | 34 | def self.add_permission(permission_string:, path: policy_file_path) 35 | policy = load_policy(path: path) 36 | if !policy["Statement"][0]["Action"].include? permission_string 37 | policy["Statement"][0]["Action"] << permission_string 38 | policy["Statement"][0]["Action"].sort! 39 | save_policy(policy: policy, path: path) 40 | else 41 | false 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/generate/terraform.rb: -------------------------------------------------------------------------------- 1 | module Generate 2 | class Terraform 3 | def self.apply_with_log(var_file:, tfvars: {}, profile: 'default', auto_approve: true, log_file: 'crash.log', credentials: '~/.aws/credentials', config: '~/.aws/config') 4 | arg_string = tfvar_arg_string(tfvars) 5 | arg_string << " -var-file=#{var_file}" unless var_file.to_s.strip.empty? 6 | arg_string << " -auto-approve" if auto_approve 7 | Helper.run!("TF_LOG_PATH=#{log_file} TF_LOG=TRACE AWS_SHARED_CREDENTIALS_FILE=#{credentials} AWS_PROFILE=#{profile} AWS_CONFIG_FILE=#{config} AWS_SDK_LOAD_CONFIG=1 terraform apply #{arg_string}") 8 | end 9 | 10 | def self.destroy_with_log(var_file:, tfvars: {}, profile: 'default', auto_approve: true, log_file: 'crash.log', credentials: '~/.aws/credentials', config: '~/.aws/config') 11 | arg_string = tfvar_arg_string(tfvars) 12 | arg_string << " -var-file=#{var_file}" unless var_file.to_s.strip.empty? 13 | arg_string << " -auto-approve" if auto_approve 14 | Helper.run!("TF_LOG_PATH=#{log_file} TF_LOG=TRACE AWS_SHARED_CREDENTIALS_FILE=#{credentials} AWS_PROFILE=#{profile} AWS_CONFIG_FILE=#{config} AWS_SDK_LOAD_CONFIG=1 terraform destroy #{arg_string}") 15 | end 16 | 17 | def self.tfvar_arg_string(tfvars) 18 | tfvars.map do |key, value| 19 | value = "'#{value.to_json}'" if value.respond_to?(:each) 20 | "-var #{key}=#{value}" 21 | end.join(' ') 22 | end 23 | 24 | def self.maybe_create_workspace(workspace_name) 25 | Logger.info("Creating #{workspace_name} workspace") 26 | Helper.run!("terraform workspace new #{workspace_name}") 27 | rescue Error 28 | Logger.info("Selecting #{workspace_name} workspace") 29 | Helper.run!("terraform workspace select #{workspace_name}") 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /policy_modifier/locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | account_id = "${data.aws_caller_identity.current.account_id}" 3 | } 4 | -------------------------------------------------------------------------------- /policy_modifier/policy.tf: -------------------------------------------------------------------------------- 1 | data "template_file" "terraform_aws_permissions_generator_permissions_policy" { 2 | template = "${file("../required_permissions.json")}" 3 | } 4 | 5 | resource "aws_iam_policy" "terraform_aws_permissions_generator_permissions_policy" { 6 | name = "terraform_aws_permissions_generator_permissions_policy" 7 | policy = "${data.template_file.terraform_aws_permissions_generator_permissions_policy.rendered}" 8 | } 9 | 10 | resource "aws_iam_role_policy_attachment" "terraform_aws_permissions_generator_role_policy" { 11 | role = "terraform_aws_permissions_generator_role" 12 | policy_arn = "${aws_iam_policy.terraform_aws_permissions_generator_permissions_policy.arn}" 13 | } 14 | -------------------------------------------------------------------------------- /policy_modifier/provider.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "${var.region}" 3 | alias = "dummy" 4 | } 5 | 6 | data "aws_caller_identity" "current" { 7 | provider = "aws.dummy" 8 | } 9 | 10 | provider "aws" { 11 | region = "${var.region}" 12 | assume_role { 13 | role_arn = "arn:aws:iam::${local.account_id}:role/terraform_aws_permissions_generator_permissions_add_role" 14 | session_name = "terraform_aws_permissions_generator" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /policy_modifier/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | description = "AWS Region" 3 | type = "string" 4 | } 5 | 6 | variable "user_name" { 7 | description = "Name of AWS user to create" 8 | default = "terraform_aws_permissions_generator" 9 | type = "string" 10 | } 11 | -------------------------------------------------------------------------------- /test_resources/ec2_instance.tf: -------------------------------------------------------------------------------- 1 | data "aws_ami" "ubuntu" { 2 | most_recent = true 3 | 4 | filter { 5 | name = "name" 6 | values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"] 7 | } 8 | 9 | filter { 10 | name = "virtualization-type" 11 | values = ["hvm"] 12 | } 13 | 14 | owners = ["099720109477"] # Canonical 15 | } 16 | 17 | resource "aws_instance" "ubuntu" { 18 | ami = "${data.aws_ami.ubuntu.id}" 19 | instance_type = "t2.micro" 20 | } 21 | -------------------------------------------------------------------------------- /test_resources/provider.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "${var.region}" 3 | } 4 | -------------------------------------------------------------------------------- /test_resources/variables.tf: -------------------------------------------------------------------------------- 1 | variable "region" { 2 | description = "AWS Region" 3 | type = "string" 4 | } 5 | --------------------------------------------------------------------------------