diff --git a/lib/terraforming.rb b/lib/terraforming.rb index c4de94ba..09271c43 100644 --- a/lib/terraforming.rb +++ b/lib/terraforming.rb @@ -45,6 +45,7 @@ require "terraforming/resource/iam_policy_attachment" require "terraforming/resource/iam_role" require "terraforming/resource/iam_role_policy" +require "terraforming/resource/iam_role_policy_attachment" require "terraforming/resource/iam_user" require "terraforming/resource/iam_user_policy" require "terraforming/resource/kms_alias" diff --git a/lib/terraforming/cli.rb b/lib/terraforming/cli.rb index ad0ad858..2dfdc3bc 100644 --- a/lib/terraforming/cli.rb +++ b/lib/terraforming/cli.rb @@ -115,6 +115,11 @@ def iamrp execute(Terraforming::Resource::IAMRolePolicy, options) end + desc "iamrpa", "IAM Role Policy Attachment" + def iamrpa + execute(Terraforming::Resource::IAMRolePolicyAttachment, options) + end + desc "iamu", "IAM User" def iamu execute(Terraforming::Resource::IAMUser, options) diff --git a/lib/terraforming/resource/iam_role_policy_attachment.rb b/lib/terraforming/resource/iam_role_policy_attachment.rb new file mode 100644 index 00000000..bc3b6d30 --- /dev/null +++ b/lib/terraforming/resource/iam_role_policy_attachment.rb @@ -0,0 +1,72 @@ +module Terraforming + module Resource + class IAMRolePolicyAttachment + include Terraforming::Util + + def self.tf(client: Aws::IAM::Client.new) + self.new(client).tf + end + + def self.tfstate(client: Aws::IAM::Client.new) + self.new(client).tfstate + end + + def initialize(client) + @client = client + end + + def tf + apply_template(@client, "tf/iam_role_policy_attachment") + end + + def tfstate + iam_role_policy_attachments.inject({}) do |resources, role_policy_attachment| + attributes = { + "id" => role_policy_attachment[:name], + "policy_arn" => role_policy_attachment[:policy_arn], + "role" => role_policy_attachment[:role] + } + resources["aws_iam_role_policy_attachment.#{module_name_of(role_policy_attachment)}"] = { + "type" => "aws_iam_role_policy_attachment", + "primary" => { + "id" => role_policy_attachment[:name], + "attributes" => attributes + } + } + + resources + end + end + + private + + def attachment_name_from(role, policy) + "#{role.role_name}-#{policy.policy_name}-attachment" + end + + def iam_roles + @client.list_roles.map(&:roles).flatten + end + + def policies_attached_to(role) + @client.list_attached_role_policies(role_name: role.role_name).attached_policies + end + + def iam_role_policy_attachments + iam_roles.map do |role| + policies_attached_to(role).map do |policy| + { + role: role.role_name, + policy_arn: policy.policy_arn, + name: attachment_name_from(role, policy) + } + end + end.flatten + end + + def module_name_of(role_policy_attachment) + normalize_module_name(role_policy_attachment[:name]) + end + end + end +end diff --git a/lib/terraforming/template/tf/iam_role_policy_attachment.erb b/lib/terraforming/template/tf/iam_role_policy_attachment.erb new file mode 100644 index 00000000..25268df4 --- /dev/null +++ b/lib/terraforming/template/tf/iam_role_policy_attachment.erb @@ -0,0 +1,7 @@ +<% iam_role_policy_attachments.each do |role_policy_attachment| -%> +resource "aws_iam_role_policy_attachment" "<%= module_name_of(role_policy_attachment) %>" { + policy_arn = "<%= role_policy_attachment[:policy_arn] %>" + role = "<%= role_policy_attachment[:role] %>" +} + +<% end -%> diff --git a/spec/lib/terraforming/cli_spec.rb b/spec/lib/terraforming/cli_spec.rb index ba1f460e..2ab68192 100644 --- a/spec/lib/terraforming/cli_spec.rb +++ b/spec/lib/terraforming/cli_spec.rb @@ -190,6 +190,13 @@ module Terraforming it_behaves_like "CLI examples" end + describe "iamrpa" do + let(:klass) { Terraforming::Resource::IAMRolePolicyAttachment } + let(:command) { :iamrpa } + + it_behaves_like "CLI examples" + end + describe "iamu" do let(:klass) { Terraforming::Resource::IAMUser } let(:command) { :iamu } diff --git a/spec/lib/terraforming/resource/iam_role_policy_attachment_spec.rb b/spec/lib/terraforming/resource/iam_role_policy_attachment_spec.rb new file mode 100644 index 00000000..5c0fbf42 --- /dev/null +++ b/spec/lib/terraforming/resource/iam_role_policy_attachment_spec.rb @@ -0,0 +1,90 @@ +require "spec_helper" + +module Terraforming + module Resource + describe IAMRolePolicyAttachment do + let(:client) do + Aws::IAM::Client.new(stub_responses: true) + end + + let(:roles) do + [ + { + path: "/", + role_name: "hoge_role", + role_id: "ABCDEFGHIJKLMN1234567", + arn: "arn:aws:iam::123456789012:role/hoge_role", + create_date: Time.parse("2015-04-01 12:34:56 UTC"), + assume_role_policy_document: "%7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D" + }, + ] + end + + let(:list_attached_role_policies_hoge) do + { + attached_policies: [ + { + policy_name: "hoge_policy", + policy_arn: "arn:aws:iam::123456789012:policy/hoge-policy" + }, + { + policy_name: "fuga_policy", + policy_arn: "arn:aws:iam::345678901234:policy/fuga-policy" + } + ] + } + end + + before do + client.stub_responses(:list_roles, roles: roles) + client.stub_responses(:list_attached_role_policies, list_attached_role_policies_hoge) + end + + describe ".tf" do + it "should generate tf" do + expect(described_class.tf(client: client)).to eq <<~EOS + resource "aws_iam_role_policy_attachment" "hoge_role-hoge_policy-attachment" { + policy_arn = "arn:aws:iam::123456789012:policy/hoge-policy" + role = "hoge_role" + } + + resource "aws_iam_role_policy_attachment" "hoge_role-fuga_policy-attachment" { + policy_arn = "arn:aws:iam::345678901234:policy/fuga-policy" + role = "hoge_role" + } + + EOS + end + end + + describe ".tfstate" do + it "should generate tfstate" do + expect(described_class.tfstate(client: client)).to eq({ + "aws_iam_role_policy_attachment.hoge_role-hoge_policy-attachment" => { + "type" => "aws_iam_role_policy_attachment", + "primary" => { + "id" => "hoge_role-hoge_policy-attachment", + "attributes" => { + "id" => "hoge_role-hoge_policy-attachment", + "policy_arn" => "arn:aws:iam::123456789012:policy/hoge-policy", + "role" => "hoge_role" + } + } + }, + "aws_iam_role_policy_attachment.hoge_role-fuga_policy-attachment" => { + "type" => "aws_iam_role_policy_attachment", + "primary" => { + "id" => "hoge_role-fuga_policy-attachment", + "attributes" => { + "id" => "hoge_role-fuga_policy-attachment", + "policy_arn" => "arn:aws:iam::345678901234:policy/fuga-policy", + "role" => "hoge_role" + } + } + } + }) + end + end + end + end +end