miamtf 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3d15ebda15963dc262d6102e00070c105f3e53ce941dd388ce423fc11545532c
4
+ data.tar.gz: 78a031aa1606b634c6c3f1157f25a2e2eb2da6536085c05f3d10cc3a0550fc89
5
+ SHA512:
6
+ metadata.gz: 21656c8b81b784010d65e761c420b0549a8c0fdf0034558e5bcf7f74eb81251ae1c0d4b23c26bd191fbc792749c3eb285394e3700bf90d629f9b86bd1768c44a
7
+ data.tar.gz: c416c8e7aa5f301ebb6b95e673c6652bc97b6264eb1d5cecf0f65403d62c3e06adcf082a590a9ec2e5e49f5ee69498f9c742b8b2e0882a1e2a3d5877b0e80d7a
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # miamtf
2
+
3
+ Miam syntax for Terraform
4
+
5
+ ## CAUTION
6
+
7
+ This is a currently released as a PoC and is **NOT** tested enough.
8
+
9
+ ## Usage
10
+
11
+ ```console
12
+ $ cat IAMfile
13
+ role "AwesomeRole" do
14
+ policy "allow-something" do
15
+ {
16
+ Version: "2012-10-17",
17
+ Statement: [
18
+ # allow something
19
+ ]
20
+ }
21
+ end
22
+ end
23
+ $ miamtf > iam.tf.json
24
+ ```
25
+
26
+ ## Acknowledgement
27
+
28
+ miamtf is highly inspired by [miam](https://github.com/codenize-tools/miam).
29
+
30
+ ## TODO
31
+
32
+ - [ ] Tests
33
+ - [ ] Documents
34
+ - Resources
35
+ - [x] Role
36
+ - [x] Managed Policy
37
+ - [x] Instance Profile
38
+ - [ ] User
39
+ - [ ] Group
40
+
41
+ ## Contribution
42
+
43
+ 日本語で OK
data/bin/miamtf ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("#{File.dirname __FILE__}/../lib")
3
+ require 'rubygems'
4
+ require 'json'
5
+ require 'optparse'
6
+ require 'miamtf'
7
+
8
+ opt = OptionParser.new
9
+
10
+ Version = Miamtf::VERSION
11
+ DEFAULT_FILENAME = 'IAMfile'
12
+ files = [DEFAULT_FILENAME]
13
+ output = nil
14
+
15
+ ARGV.options do |opt|
16
+ opt.on('-f', '--file FILE') {|v| files = [v]}
17
+ opt.on('-w', '--write OUTPUT') do |v|
18
+ output = v
19
+ files = ARGV unless ARGV.empty?
20
+ end
21
+ opt.parse!
22
+ end
23
+
24
+ files.each do |file|
25
+ fullpath = File.expand_path(file)
26
+ rb_source = File.read(fullpath)
27
+ Dir.chdir(File.dirname(file)) do
28
+ json = JSON::pretty_generate(Miamtf::DSL::Context.eval(rb_source, fullpath).to_h)
29
+ if output.nil?
30
+ puts json
31
+ else
32
+ File.write(output, json)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("#{File.dirname __FILE__}/../lib")
3
+ require 'rubygems'
4
+ require 'json'
5
+ require 'miamtf'
6
+
7
+ Version = Miamtf::VERSION
8
+
9
+ tf = JSON.parse(STDIN.read, symbolize_names: true)
10
+ local = tf[:locals][:miamtf]
11
+
12
+ # The feature to migrate is very adhoc and not well defined.
13
+ roles = local[:roles]
14
+ policies = local[:managed_policies]
15
+ instance_profiles = local[:instance_profiles]
16
+
17
+ moved_roles = roles.keys.map do |role_name|
18
+ <<~HCL
19
+ moved {
20
+ from = aws_iam_role.#{role_name}
21
+ to = aws_iam_role.miamtf["#{role_name}"]
22
+ }
23
+ HCL
24
+ end
25
+ moved_policies = policies.keys.map do |policy_name|
26
+ <<~HCL
27
+ moved {
28
+ from = aws_iam_policy.#{policy_name}
29
+ to = aws_iam_policy.miamtf["#{policy_name}"]
30
+ }
31
+ HCL
32
+ end
33
+ moved_instance_profiles = instance_profiles.keys.map do |instance_profile_name|
34
+ <<~HCL
35
+ moved {
36
+ from = aws_iam_instance_profile.#{instance_profile_name}
37
+ to = aws_iam_instance_profile.miamtf["#{instance_profile_name}"]
38
+ }
39
+ HCL
40
+ end
41
+
42
+ content = (moved_roles + moved_policies + moved_instance_profiles).join("\n")
43
+
44
+ STDOUT.puts content
data/lib/miamtf/aux.tf ADDED
@@ -0,0 +1,107 @@
1
+ # This file is to be converted into JSON with hcl2json
2
+ # hcl2json: https://github.com/tmccombs/hcl2json
3
+
4
+ resource "aws_iam_role" "miamtf" {
5
+ for_each = local.miamtf.roles
6
+
7
+ # implicit
8
+ name = each.key
9
+
10
+ # required
11
+ assume_role_policy = jsonencode(each.value.assume_role_policy)
12
+
13
+ # optional
14
+ description = each.value.description
15
+ force_detach_policies = each.value.force_detach_policies
16
+ max_session_duration = each.value.max_session_duration
17
+ path = each.value.path
18
+ permissions_boundary = each.value.permissions_boundary
19
+ tags = each.value.tags
20
+ }
21
+
22
+ resource "aws_iam_role_policy" "miamtf" {
23
+ for_each = {
24
+ for v in flatten([
25
+ for role_name, role in local.miamtf.roles : [
26
+ for policy_name, policy_document in role.inline_policies : {
27
+ role_name = role_name
28
+ policy_name = policy_name
29
+ policy_document = policy_document
30
+ }
31
+ ]
32
+ ]) : "${v.role_name}|${v.policy_name}" => v
33
+ }
34
+
35
+ # implicit
36
+ name = each.value.policy_name
37
+ role = each.value.role_name
38
+
39
+ # required
40
+ policy = jsonencode(each.value.policy_document)
41
+ }
42
+
43
+ resource "aws_iam_role_policies_exclusive" "miamtf" {
44
+ for_each = local.miamtf.roles
45
+
46
+ # implicit
47
+ role_name = each.key
48
+
49
+ # required
50
+ policy_names = keys(each.value.inline_policies)
51
+ }
52
+
53
+ resource "aws_iam_role_policy_attachment" "miamtf" {
54
+ for_each = {
55
+ for v in flatten([
56
+ for role_name, role in local.miamtf.roles : [
57
+ for policy_arn in role.managed_policy_arns : {
58
+ role_name = role_name
59
+ policy_arn = policy_arn
60
+ }
61
+ ]
62
+ ]) : "${v.role_name}|${v.policy_arn}" => v
63
+ }
64
+
65
+ # implicit
66
+ role = each.value.role_name
67
+
68
+ # required
69
+ policy_arn = each.value.policy_arn
70
+ }
71
+
72
+ resource "aws_iam_role_policy_attachments_exclusive" "miamtf" {
73
+ for_each = local.miamtf.roles
74
+
75
+ # implicit
76
+ role_name = each.key
77
+
78
+ # required
79
+ policy_arns = each.value.managed_policy_arns
80
+ }
81
+
82
+ resource "aws_iam_policy" "miamtf" {
83
+ for_each = local.miamtf.managed_policies
84
+
85
+ # implicit
86
+ name = each.key
87
+
88
+ # required
89
+ policy = jsonencode(each.value.policy_document)
90
+
91
+ # optional
92
+ description = each.value.description
93
+ path = each.value.path
94
+ tags = each.value.tags
95
+ }
96
+
97
+ resource "aws_iam_instance_profile" "miamtf" {
98
+ for_each = local.miamtf.instance_profiles
99
+
100
+ # implicit
101
+ name = each.key
102
+ role = each.key
103
+
104
+ # optional
105
+ path = each.value.path
106
+ tags = each.value.tags
107
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "resource": {
3
+ "aws_iam_instance_profile": {
4
+ "miamtf": [
5
+ {
6
+ "for_each": "${local.miamtf.instance_profiles}",
7
+ "name": "${each.key}",
8
+ "path": "${each.value.path}",
9
+ "role": "${each.key}",
10
+ "tags": "${each.value.tags}"
11
+ }
12
+ ]
13
+ },
14
+ "aws_iam_policy": {
15
+ "miamtf": [
16
+ {
17
+ "description": "${each.value.description}",
18
+ "for_each": "${local.miamtf.managed_policies}",
19
+ "name": "${each.key}",
20
+ "path": "${each.value.path}",
21
+ "policy": "${jsonencode(each.value.policy_document)}",
22
+ "tags": "${each.value.tags}"
23
+ }
24
+ ]
25
+ },
26
+ "aws_iam_role": {
27
+ "miamtf": [
28
+ {
29
+ "assume_role_policy": "${jsonencode(each.value.assume_role_policy)}",
30
+ "description": "${each.value.description}",
31
+ "for_each": "${local.miamtf.roles}",
32
+ "force_detach_policies": "${each.value.force_detach_policies}",
33
+ "max_session_duration": "${each.value.max_session_duration}",
34
+ "name": "${each.key}",
35
+ "path": "${each.value.path}",
36
+ "permissions_boundary": "${each.value.permissions_boundary}",
37
+ "tags": "${each.value.tags}"
38
+ }
39
+ ]
40
+ },
41
+ "aws_iam_role_policies_exclusive": {
42
+ "miamtf": [
43
+ {
44
+ "for_each": "${local.miamtf.roles}",
45
+ "policy_names": "${keys(each.value.inline_policies)}",
46
+ "role_name": "${each.key}"
47
+ }
48
+ ]
49
+ },
50
+ "aws_iam_role_policy": {
51
+ "miamtf": [
52
+ {
53
+ "for_each": "${{\n for v in flatten([\n for role_name, role in local.miamtf.roles : [\n for policy_name, policy_document in role.inline_policies : {\n role_name = role_name\n policy_name = policy_name\n policy_document = policy_document\n }\n ]\n ]) : \"${v.role_name}|${v.policy_name}\" =\u003e v\n }}",
54
+ "name": "${each.value.policy_name}",
55
+ "policy": "${jsonencode(each.value.policy_document)}",
56
+ "role": "${each.value.role_name}"
57
+ }
58
+ ]
59
+ },
60
+ "aws_iam_role_policy_attachment": {
61
+ "miamtf": [
62
+ {
63
+ "for_each": "${{\n for v in flatten([\n for role_name, role in local.miamtf.roles : [\n for policy_arn in role.managed_policy_arns : {\n role_name = role_name\n policy_arn = policy_arn\n }\n ]\n ]) : \"${v.role_name}|${v.policy_arn}\" =\u003e v\n }}",
64
+ "policy_arn": "${each.value.policy_arn}",
65
+ "role": "${each.value.role_name}"
66
+ }
67
+ ]
68
+ },
69
+ "aws_iam_role_policy_attachments_exclusive": {
70
+ "miamtf": [
71
+ {
72
+ "for_each": "${local.miamtf.roles}",
73
+ "policy_arns": "${each.value.managed_policy_arns}",
74
+ "role_name": "${each.key}"
75
+ }
76
+ ]
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,11 @@
1
+ class Miamtf::DSL::Context::ManagedPolicy
2
+ def initialize(&block)
3
+ @policy = instance_eval(&block)
4
+ end
5
+
6
+ def to_h
7
+ {
8
+ policy_document: @policy,
9
+ }
10
+ end
11
+ end
@@ -0,0 +1,43 @@
1
+ class Miamtf::DSL::Context::Role
2
+ def initialize(&block)
3
+ @assume_role_policy_document = nil
4
+ @max_session_duration = nil
5
+ @attached_managed_policies = []
6
+ @policies = {}
7
+ @tags = {}
8
+ instance_eval(&block)
9
+ end
10
+
11
+ def to_h
12
+ {
13
+ assume_role_policy: @assume_role_policy_document,
14
+ inline_policies: @policies,
15
+ managed_policy_arns: @attached_managed_policies,
16
+ max_session_duration: @max_session_duration,
17
+ tags: @tags,
18
+ }
19
+ end
20
+
21
+ private
22
+ def assume_role_policy_document
23
+ @assume_role_policy_document = yield
24
+ end
25
+
26
+ def max_session_duration(duration)
27
+ @max_session_duration = duration
28
+ end
29
+
30
+ def attached_managed_policies(*policies)
31
+ @attached_managed_policies.concat(policies.map(&:to_s))
32
+ end
33
+
34
+ def policy(name)
35
+ name = name.to_s
36
+
37
+ @policies[name] = yield
38
+ end
39
+
40
+ def tags(tags)
41
+ @tags = tags
42
+ end
43
+ end
@@ -0,0 +1,75 @@
1
+ class Miamtf::DSL::Context
2
+ def self.eval(source, path)
3
+ self.new(path) do
4
+ eval(source, binding, path)
5
+ end
6
+ end
7
+
8
+ def initialize(path, &block)
9
+ @path = path
10
+ @roles = {}
11
+ @policies = {}
12
+ @instance_profiles = {}
13
+
14
+ instance_eval(&block)
15
+ end
16
+
17
+ def to_h
18
+ aux_tf = JSON.load_file(
19
+ File.join(File.dirname(__FILE__), '../aux.tf.json')
20
+ )
21
+
22
+ model = Miamtf::Model::Root.new(
23
+ roles: @roles,
24
+ managed_policies: @policies,
25
+ instance_profiles: @instance_profiles,
26
+ )
27
+ locals = {
28
+ miamtf: model.to_h
29
+ }
30
+
31
+ aux_tf.merge(locals: locals)
32
+ end
33
+
34
+ private
35
+
36
+ def require(file)
37
+ original_path = File.expand_path(file, File.dirname(@path))
38
+ candidates = [
39
+ original_path,
40
+ original_path + ".rb",
41
+ ]
42
+ path = candidates.find {|path| File.exist?(path) }
43
+ if path
44
+ instance_eval(File.read(path), path)
45
+ else
46
+ Kernel.require(file)
47
+ end
48
+ end
49
+
50
+ def role(name, **role_options, &block)
51
+ name = name.to_s
52
+
53
+ role = Role.new(&block)
54
+ @roles[name] = Miamtf::Model::Role::new(
55
+ role_options.merge(role.to_h)
56
+ )
57
+ end
58
+
59
+ def instance_profile(name, **instance_profile_options)
60
+ name = name.to_s
61
+
62
+ @instance_profiles[name] = Miamtf::Model::InstanceProfile.new(
63
+ instance_profile_options
64
+ )
65
+ end
66
+
67
+ def managed_policy(name, **policy_options, &block)
68
+ name = name.to_s
69
+
70
+ managed_policy = ManagedPolicy.new(&block)
71
+ @policies[name] = Miamtf::Model::ManagedPolicy.new(
72
+ policy_options.merge(managed_policy.to_h)
73
+ )
74
+ end
75
+ end
data/lib/miamtf/dsl.rb ADDED
@@ -0,0 +1 @@
1
+ module Miamtf::DSL; end
@@ -0,0 +1,50 @@
1
+ module Miamtf::Model
2
+ Root = Struct.new(
3
+ :roles, # map<string(role name), role: Role>
4
+ :managed_policies, # map<string(policy name), ManagedPolicy>
5
+ :instance_profiles, # map<string(profile name), InstanceProfile>
6
+
7
+ keyword_init: true
8
+ ) do
9
+ def to_h
10
+ {
11
+ roles: roles.transform_values(&:to_h),
12
+ managed_policies: managed_policies.transform_values(&:to_h),
13
+ instance_profiles: instance_profiles.transform_values(&:to_h),
14
+ }
15
+ end
16
+ end
17
+ Role = Struct.new(
18
+ # required
19
+ :assume_role_policy, # object(policy document to be converted to JSON)
20
+ # optional
21
+ :description, # string
22
+ :force_detach_policies, # boolean
23
+ :max_session_duration, # integer
24
+ :path, # string
25
+ :permissions_boundary, # string(ARN)
26
+ :tags, # map<string(name), string(value)>
27
+ # virtual
28
+ :inline_policies, # map<string(policy name), object(policy document to be converted to JSON)>
29
+ :managed_policy_arns, # list<string(ARN)>
30
+
31
+ keyword_init: true
32
+ )
33
+ ManagedPolicy = Struct.new(
34
+ # required
35
+ :policy_document, # object(policy document to be converted to JSON)
36
+ # optional
37
+ :description, # string
38
+ :path, # string
39
+ :tags, # map<string(name), string(value)>
40
+
41
+ keyword_init: true
42
+ )
43
+ InstanceProfile = Struct.new(
44
+ # optional
45
+ :path, # string
46
+ :tags, # map<string(name), string(value)>
47
+
48
+ keyword_init: true
49
+ )
50
+ end
@@ -0,0 +1,3 @@
1
+ module Miamtf
2
+ VERSION = "0.2.0"
3
+ end
data/lib/miamtf.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Miamtf; end
2
+ require "miamtf/version"
3
+ require "miamtf/model"
4
+ require "miamtf/dsl"
5
+ require "miamtf/dsl/context"
6
+ require "miamtf/dsl/context/role"
7
+ require "miamtf/dsl/context/managed_policy"
data/miamtf.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ require_relative "lib/miamtf/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'miamtf'
5
+ spec.version = Miamtf::VERSION
6
+ spec.authors = ['Hidekazu Kobayashi']
7
+ spec.email = ['kobahide789@gmail.com']
8
+ spec.summary = 'Miam syntax for Terraform'
9
+ spec.homepage = 'https://github.com/KOBA789/miamtf'
10
+ spec.license = 'MIT'
11
+
12
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
13
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
14
+ end
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ['lib']
18
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: miamtf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Hidekazu Kobayashi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-04-11 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - kobahide789@gmail.com
16
+ executables:
17
+ - miamtf
18
+ - miamtf-migrate
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - README.md
23
+ - bin/miamtf
24
+ - bin/miamtf-migrate
25
+ - lib/miamtf.rb
26
+ - lib/miamtf/aux.tf
27
+ - lib/miamtf/aux.tf.json
28
+ - lib/miamtf/dsl.rb
29
+ - lib/miamtf/dsl/context.rb
30
+ - lib/miamtf/dsl/context/managed_policy.rb
31
+ - lib/miamtf/dsl/context/role.rb
32
+ - lib/miamtf/model.rb
33
+ - lib/miamtf/version.rb
34
+ - miamtf.gemspec
35
+ homepage: https://github.com/KOBA789/miamtf
36
+ licenses:
37
+ - MIT
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.4.6
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Miam syntax for Terraform
58
+ test_files: []