terrafying-components 1.4.3 → 1.4.4
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 +4 -4
- data/lib/hash/merge_with_arrays.rb +7 -0
- data/lib/terrafying/components.rb +10 -0
- data/lib/terrafying/components/auditd.rb +158 -0
- data/lib/terrafying/components/ca.rb +55 -0
- data/lib/terrafying/components/dynamicset.rb +229 -0
- data/lib/terrafying/components/endpoint.rb +96 -0
- data/lib/terrafying/components/endpointservice.rb +63 -0
- data/lib/terrafying/components/ignition.rb +117 -0
- data/lib/terrafying/components/instance.rb +112 -0
- data/lib/terrafying/components/instanceprofile.rb +81 -0
- data/lib/terrafying/components/letsencrypt.rb +146 -0
- data/lib/terrafying/components/loadbalancer.rb +159 -0
- data/lib/terrafying/components/ports.rb +35 -0
- data/lib/terrafying/components/selfsignedca.rb +171 -0
- data/lib/terrafying/components/service.rb +148 -0
- data/lib/terrafying/components/staticset.rb +153 -0
- data/lib/terrafying/components/subnet.rb +105 -0
- data/lib/terrafying/components/support/deregister-vpn +48 -0
- data/lib/terrafying/components/support/register-vpn +46 -0
- data/lib/terrafying/components/templates/ignition.yaml +115 -0
- data/lib/terrafying/components/usable.rb +129 -0
- data/lib/terrafying/components/version.rb +5 -0
- data/lib/terrafying/components/vpc.rb +417 -0
- data/lib/terrafying/components/vpn.rb +358 -0
- data/lib/terrafying/components/zone.rb +144 -0
- metadata +28 -31
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
require 'terrafying/components/loadbalancer'
|
3
|
+
require 'terrafying/components/usable'
|
4
|
+
require 'terrafying/components/vpc'
|
5
|
+
require 'terrafying/generator'
|
6
|
+
|
7
|
+
module Terrafying
|
8
|
+
|
9
|
+
module Components
|
10
|
+
|
11
|
+
class Endpoint < Terrafying::Context
|
12
|
+
|
13
|
+
attr_reader :security_group
|
14
|
+
|
15
|
+
include Usable
|
16
|
+
|
17
|
+
def self.create_in(vpc, name, options={})
|
18
|
+
Endpoint.new.create_in(vpc, name, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_in(vpc, name, options={})
|
26
|
+
options = {
|
27
|
+
auto_accept: true,
|
28
|
+
subnets: vpc.subnets.fetch(:private, []),
|
29
|
+
private_dns: false,
|
30
|
+
dns_name: name,
|
31
|
+
tags: {},
|
32
|
+
}.merge(options)
|
33
|
+
|
34
|
+
ident = "#{tf_safe(vpc.name)}-#{name}"
|
35
|
+
@name = name
|
36
|
+
|
37
|
+
if options[:service]
|
38
|
+
service_name = options[:service].service_name
|
39
|
+
|
40
|
+
@ports = options[:service].load_balancer.ports
|
41
|
+
elsif options[:service_name]
|
42
|
+
service_name = options[:service_name]
|
43
|
+
|
44
|
+
if options[:service_name].start_with?("com.amazonaws")
|
45
|
+
@ports = enrich_ports([443])
|
46
|
+
else
|
47
|
+
endpoint_service = aws.endpoint_service_by_name(options[:service_name])
|
48
|
+
|
49
|
+
target_groups = endpoint_service.network_load_balancer_arns.map { |arn|
|
50
|
+
aws.target_groups_by_lb(arn)
|
51
|
+
}.flatten
|
52
|
+
|
53
|
+
@ports = enrich_ports(target_groups.map(&:port))
|
54
|
+
end
|
55
|
+
elsif options[:source]
|
56
|
+
if options[:source].is_a?(VPC)
|
57
|
+
source = { vpc: options[:source], name: name }
|
58
|
+
else
|
59
|
+
source = options[:source]
|
60
|
+
end
|
61
|
+
|
62
|
+
lb = LoadBalancer.find_in(source[:vpc], source[:name])
|
63
|
+
|
64
|
+
@ports = lb.ports
|
65
|
+
service_name = aws.endpoint_service_by_lb_arn(lb.id).service_name
|
66
|
+
else
|
67
|
+
raise "You need to pass either a service_name or source option to create an endpoint"
|
68
|
+
end
|
69
|
+
|
70
|
+
@security_group = resource :aws_security_group, ident, {
|
71
|
+
name: "endpoint-#{ident}",
|
72
|
+
description: "Describe the ingress and egress of the endpoint #{ident}",
|
73
|
+
tags: options[:tags],
|
74
|
+
vpc_id: vpc.id,
|
75
|
+
}
|
76
|
+
|
77
|
+
resource :aws_vpc_endpoint, ident, {
|
78
|
+
vpc_id: vpc.id,
|
79
|
+
service_name: service_name,
|
80
|
+
vpc_endpoint_type: "Interface",
|
81
|
+
security_group_ids: [ @security_group ],
|
82
|
+
auto_accept: options[:auto_accept],
|
83
|
+
subnet_ids: options[:subnets].map(&:id),
|
84
|
+
private_dns_enabled: options[:private_dns],
|
85
|
+
}
|
86
|
+
|
87
|
+
vpc.zone.add_cname_in(self, options[:dns_name], output_of(:aws_vpc_endpoint, ident, "dns_entry.0.dns_name"))
|
88
|
+
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
|
2
|
+
require 'terrafying/generator'
|
3
|
+
|
4
|
+
module Terrafying
|
5
|
+
|
6
|
+
module Components
|
7
|
+
|
8
|
+
class EndpointService < Terrafying::Context
|
9
|
+
|
10
|
+
attr_reader :name, :load_balancer, :service_name
|
11
|
+
|
12
|
+
def self.create_for(load_balancer, name, options={})
|
13
|
+
EndpointService.new.create_for(load_balancer, name, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(service_name)
|
17
|
+
EndpointService.new.find(service_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def find(service_name)
|
25
|
+
raise 'unimplemented'
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_for(load_balancer, name, options={})
|
29
|
+
options = {
|
30
|
+
acceptance_required: true,
|
31
|
+
allowed_principals: [
|
32
|
+
"arn:aws:iam::#{aws.account_id}:root",
|
33
|
+
],
|
34
|
+
}.merge(options)
|
35
|
+
|
36
|
+
if ! load_balancer or load_balancer.type != "network"
|
37
|
+
raise "The load balancer needs to be a network load balancer"
|
38
|
+
end
|
39
|
+
|
40
|
+
@name = name
|
41
|
+
@load_balancer = load_balancer
|
42
|
+
|
43
|
+
resource :aws_vpc_endpoint_service, name, {
|
44
|
+
acceptance_required: options[:acceptance_required],
|
45
|
+
allowed_principals: options[:allowed_principals],
|
46
|
+
network_load_balancer_arns: [load_balancer.id],
|
47
|
+
}
|
48
|
+
|
49
|
+
@service_name = output_of(:aws_vpc_endpoint_service, name, "service_name")
|
50
|
+
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def expose_in(vpc, options={})
|
55
|
+
name = options.fetch(:name, @name)
|
56
|
+
add! Endpoint.create_in(vpc, name, options.merge({ service: self }))
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module Terrafying
|
5
|
+
|
6
|
+
module Components
|
7
|
+
|
8
|
+
class Ignition
|
9
|
+
|
10
|
+
UNIT_REQUIRED_KEYS = [:name]
|
11
|
+
FILE_REQUIRED_KEYS = [:path, :mode, :contents]
|
12
|
+
|
13
|
+
def self.container_unit(name, image, options={})
|
14
|
+
options = {
|
15
|
+
volumes: [],
|
16
|
+
environment_variables: [],
|
17
|
+
arguments: [],
|
18
|
+
require_units: [],
|
19
|
+
host_networking: false,
|
20
|
+
privileged: false,
|
21
|
+
}.merge(options)
|
22
|
+
|
23
|
+
if options[:require_units].count > 0
|
24
|
+
require_units = options[:require_units].join(" ")
|
25
|
+
require = <<EOF
|
26
|
+
After=#{require_units}
|
27
|
+
Requires=#{require_units}
|
28
|
+
EOF
|
29
|
+
end
|
30
|
+
|
31
|
+
docker_options = []
|
32
|
+
|
33
|
+
if options[:environment_variables].count > 0
|
34
|
+
docker_options += options[:environment_variables].map { |var|
|
35
|
+
"-e #{var}"
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
if options[:volumes].count > 0
|
40
|
+
docker_options += options[:volumes].map { |volume|
|
41
|
+
"-v #{volume}"
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
if options[:host_networking]
|
46
|
+
docker_options << "--net=host"
|
47
|
+
end
|
48
|
+
|
49
|
+
if options[:privileged]
|
50
|
+
docker_options << "--privileged"
|
51
|
+
end
|
52
|
+
|
53
|
+
docker_options_str = " \\\n" + docker_options.join(" \\\n")
|
54
|
+
|
55
|
+
if options[:arguments].count > 0
|
56
|
+
arguments = " \\\n" + options[:arguments].join(" \\\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
{
|
60
|
+
name: "#{name}.service",
|
61
|
+
contents: <<EOF
|
62
|
+
[Install]
|
63
|
+
WantedBy=multi-user.target
|
64
|
+
|
65
|
+
[Unit]
|
66
|
+
Description=#{name}
|
67
|
+
#{require}
|
68
|
+
|
69
|
+
[Service]
|
70
|
+
ExecStartPre=-/usr/bin/docker rm -f #{name}
|
71
|
+
ExecStart=/usr/bin/docker run --name #{name} #{docker_options_str} \
|
72
|
+
#{image} #{arguments}
|
73
|
+
Restart=always
|
74
|
+
RestartSec=30
|
75
|
+
|
76
|
+
EOF
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.generate(options={})
|
81
|
+
options = {
|
82
|
+
keypairs: [],
|
83
|
+
volumes: [],
|
84
|
+
files: [],
|
85
|
+
units: [],
|
86
|
+
ssh_group: "cloud",
|
87
|
+
disable_update_engine: false,
|
88
|
+
region: Terrafying::Generator.aws.region,
|
89
|
+
}.merge(options)
|
90
|
+
|
91
|
+
if ! options[:units].all? { |u| UNIT_REQUIRED_KEYS.all? { |key| u.has_key?(key) } }
|
92
|
+
raise "All units require the following keys: #{UNIT_REQUIRED_KEYS}"
|
93
|
+
end
|
94
|
+
|
95
|
+
if ! options[:units].all? { |u| u.has_key?(:contents) || u.has_key?(:dropins) }
|
96
|
+
raise "All units have to have contents and/or dropins"
|
97
|
+
end
|
98
|
+
|
99
|
+
if ! options[:files].all? { |f| FILE_REQUIRED_KEYS.all? { |key| f.has_key?(key) } }
|
100
|
+
raise "All files require the following keys: #{FILE_REQUIRED_KEYS}"
|
101
|
+
end
|
102
|
+
|
103
|
+
options[:cas] = options[:keypairs].map { |kp| kp[:ca] }.sort.uniq
|
104
|
+
|
105
|
+
erb_path = File.join(File.dirname(__FILE__), "templates/ignition.yaml")
|
106
|
+
erb = ERB.new(IO.read(erb_path))
|
107
|
+
|
108
|
+
yaml = erb.result(OpenStruct.new(options).instance_eval { binding })
|
109
|
+
|
110
|
+
Terrafying::Util.to_ignition(yaml)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
|
2
|
+
require 'terrafying/components/usable'
|
3
|
+
|
4
|
+
module Terrafying
|
5
|
+
|
6
|
+
module Components
|
7
|
+
|
8
|
+
class Instance < Terrafying::Context
|
9
|
+
|
10
|
+
attr_reader :id, :name, :ip_address, :subnet
|
11
|
+
|
12
|
+
include Usable
|
13
|
+
|
14
|
+
def self.create_in(vpc, name, options={})
|
15
|
+
Instance.new.create_in vpc, name, options
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find_in(vpc, name)
|
19
|
+
Instance.new.find_in vpc, name
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize()
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_in(vpc, name)
|
27
|
+
raise 'unimplemented'
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_in(vpc, name, options={})
|
31
|
+
options = {
|
32
|
+
public: false,
|
33
|
+
instance_type: "t2.micro",
|
34
|
+
instance_profile: nil,
|
35
|
+
ports: [],
|
36
|
+
tags: {},
|
37
|
+
security_groups: [],
|
38
|
+
depends_on: [],
|
39
|
+
}.merge(options)
|
40
|
+
|
41
|
+
ident = "#{tf_safe(vpc.name)}-#{name}"
|
42
|
+
|
43
|
+
@name = name
|
44
|
+
@ports = enrich_ports(options[:ports])
|
45
|
+
|
46
|
+
@security_group = resource :aws_security_group, ident, {
|
47
|
+
name: "instance-#{ident}",
|
48
|
+
description: "Describe the ingress and egress of the instance #{ident}",
|
49
|
+
tags: options[:tags],
|
50
|
+
vpc_id: vpc.id,
|
51
|
+
egress: [
|
52
|
+
{
|
53
|
+
from_port: 0,
|
54
|
+
to_port: 0,
|
55
|
+
protocol: -1,
|
56
|
+
cidr_blocks: ["0.0.0.0/0"],
|
57
|
+
}
|
58
|
+
],
|
59
|
+
}
|
60
|
+
|
61
|
+
path_mtu_setup!
|
62
|
+
|
63
|
+
if options.has_key? :ip_address
|
64
|
+
lifecycle = {
|
65
|
+
lifecycle: { create_before_destroy: false },
|
66
|
+
}
|
67
|
+
else
|
68
|
+
lifecycle = {
|
69
|
+
lifecycle: { create_before_destroy: true },
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
if options.has_key? :subnet
|
74
|
+
@subnet = options[:subnet]
|
75
|
+
else
|
76
|
+
subnets = options.fetch(:subnets, vpc.subnets[:private])
|
77
|
+
# pick something consistent but not just the first subnet
|
78
|
+
subnet_index = XXhash.xxh32(ident) % subnets.count
|
79
|
+
@subnet = subnets[subnet_index]
|
80
|
+
end
|
81
|
+
|
82
|
+
@id = resource :aws_instance, ident, {
|
83
|
+
ami: options[:ami],
|
84
|
+
instance_type: options[:instance_type],
|
85
|
+
iam_instance_profile: options[:instance_profile] && options[:instance_profile].id,
|
86
|
+
subnet_id: @subnet.id,
|
87
|
+
associate_public_ip_address: options[:public],
|
88
|
+
root_block_device: {
|
89
|
+
volume_type: 'gp2',
|
90
|
+
volume_size: 32,
|
91
|
+
},
|
92
|
+
tags: {
|
93
|
+
'Name' => ident,
|
94
|
+
}.merge(options[:tags]),
|
95
|
+
vpc_security_group_ids: [
|
96
|
+
vpc.internal_ssh_security_group,
|
97
|
+
].push(*options[:security_groups]),
|
98
|
+
user_data: options[:user_data],
|
99
|
+
lifecycle: {
|
100
|
+
create_before_destroy: true,
|
101
|
+
},
|
102
|
+
depends_on: options[:depends_on],
|
103
|
+
}.merge(options[:ip_address] ? { private_ip: options[:ip_address] } : {}).merge(lifecycle)
|
104
|
+
|
105
|
+
@ip_address = output_of(:aws_instance, ident, options[:public] ? :public_ip : :private_ip)
|
106
|
+
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
module Terrafying
|
3
|
+
|
4
|
+
module Components
|
5
|
+
|
6
|
+
class InstanceProfile < Terrafying::Context
|
7
|
+
|
8
|
+
attr_reader :id
|
9
|
+
|
10
|
+
def self.create(name, options={})
|
11
|
+
InstanceProfile.new.create name, options
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.find(name)
|
15
|
+
InstanceProfile.new.find name
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize()
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def find(name)
|
23
|
+
raise 'unimplemented'
|
24
|
+
end
|
25
|
+
|
26
|
+
def create(name, options={})
|
27
|
+
options = {
|
28
|
+
statements: [],
|
29
|
+
}.merge(options)
|
30
|
+
|
31
|
+
resource :aws_iam_role, name, {
|
32
|
+
name: name,
|
33
|
+
assume_role_policy: JSON.pretty_generate(
|
34
|
+
{
|
35
|
+
Version: "2012-10-17",
|
36
|
+
Statement: [
|
37
|
+
{
|
38
|
+
Effect: "Allow",
|
39
|
+
Principal: { "Service": "ec2.amazonaws.com"},
|
40
|
+
Action: "sts:AssumeRole"
|
41
|
+
}
|
42
|
+
]
|
43
|
+
}
|
44
|
+
)
|
45
|
+
}
|
46
|
+
|
47
|
+
resource :aws_iam_role_policy, name, {
|
48
|
+
name: name,
|
49
|
+
policy: JSON.pretty_generate(
|
50
|
+
{
|
51
|
+
Version: "2012-10-17",
|
52
|
+
Statement: [
|
53
|
+
{
|
54
|
+
Sid: "Stmt1442396947000",
|
55
|
+
Effect: "Allow",
|
56
|
+
Action: [
|
57
|
+
"iam:GetGroup",
|
58
|
+
"iam:GetSSHPublicKey",
|
59
|
+
"iam:GetUser",
|
60
|
+
"iam:ListSSHPublicKeys"
|
61
|
+
],
|
62
|
+
Resource: [
|
63
|
+
"arn:aws:iam::*"
|
64
|
+
]
|
65
|
+
}
|
66
|
+
].push(*options[:statements])
|
67
|
+
}
|
68
|
+
),
|
69
|
+
role: output_of(:aws_iam_role, name, :name)
|
70
|
+
}
|
71
|
+
|
72
|
+
@id = resource :aws_iam_instance_profile, name, {
|
73
|
+
name: name,
|
74
|
+
role: output_of(:aws_iam_role, name, :name),
|
75
|
+
}
|
76
|
+
|
77
|
+
self
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|