Skip to content

Commit 0a41d4e

Browse files
authored
Merge pull request #382 from ComputeCanada/bastions
Use all potential bastion tags instead of only the first match
2 parents 072c057 + 2df7b50 commit 0a41d4e

13 files changed

Lines changed: 65 additions & 39 deletions

File tree

aws/infrastructure.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module "design" {
1313
pool = var.pool
1414
volumes = var.volumes
1515
firewall_rules = var.firewall_rules
16+
bastion_tags = var.bastion_tags
1617
}
1718

1819
module "configuration" {
@@ -24,7 +25,7 @@ module "configuration" {
2425
sudoer_username = var.sudoer_username
2526
public_keys = var.public_keys
2627
domain_name = module.design.domain_name
27-
bastion_tag = module.design.bastion_tag
28+
bastion_tags = module.design.bastion_tags
2829
cluster_name = var.cluster_name
2930
guest_passwd = var.guest_passwd
3031
nb_users = var.nb_users

azure/infrastructure.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module "design" {
1313
pool = var.pool
1414
volumes = var.volumes
1515
firewall_rules = var.firewall_rules
16+
bastion_tags = var.bastion_tags
1617
}
1718

1819
module "configuration" {
@@ -24,7 +25,7 @@ module "configuration" {
2425
sudoer_username = var.sudoer_username
2526
public_keys = var.public_keys
2627
domain_name = module.design.domain_name
27-
bastion_tag = module.design.bastion_tag
28+
bastion_tags = module.design.bastion_tags
2829
cluster_name = var.cluster_name
2930
guest_passwd = var.guest_passwd
3031
nb_users = var.nb_users

common/configuration/main.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ variable "public_keys" {}
2424

2525
variable "skip_upgrade" {}
2626
variable "puppetfile" {}
27-
variable "bastion_tag" {}
27+
variable "bastion_tags" {}
2828

2929
resource "tls_private_key" "ssh" {
3030
algorithm = "ED25519"
@@ -162,7 +162,7 @@ output "ssh_key" {
162162
output "bastions" {
163163
value = {
164164
for host, values in local.final_inventory : host => values
165-
if contains(values.tags, var.bastion_tag) && contains(values.tags, "public") && (!contains(values.tags, "pool"))
165+
if length(setintersection(values.tags, var.bastion_tags)) > 0 && (!contains(values.tags, "pool"))
166166
}
167167
}
168168

common/design/main.tf

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,21 @@ locals {
5252

5353
volume_per_instance = transpose({ for key, value in local.instance_per_volume : key => value["instances"] })
5454

55-
# We look for a firewall rule that allow SSH connection from the Terraform agent's ip
56-
# and we memorize the corresponding tag so we can determine which instances can be used as a
55+
# We look for firewall rules that allow SSH connection from the Terraform agent's ip
56+
# and we memorize the corresponding tags so we can determine which instances can be used as a
5757
# first hop when transferring files or executing remote commands with Terraform.
58-
# There are room for improvements, but we don't expect users to be very creative with
59-
# firewall rules, so we are keeping the algorithm simple for now. One aspect
60-
# that could be improved:
61-
# 1. We don't validate if the tag is actually present in any instance, we simply take the
62-
# first value, so if there are more than one firewall rules that matches the criteria
63-
# but only one that is actually active, we might select the wrong tag. It would be better
64-
# to keep all firewall tags that match the criteria, then identify the intersection with
65-
# instance tags and select any tag that matches.
6658
agent_ip = chomp(data.http.agent_ip.response_body)
67-
bastion_tag = try(
68-
element([
69-
for rule, values in var.firewall_rules :
70-
values.tag
71-
if values.ethertype == "IPv4" &&
72-
22 <= values.from_port && values.to_port <= 22 &&
73-
alltrue([
74-
for i, v in split(".", local.agent_ip) :
75-
tonumber(split(".", strcontains(values.cidr, "/") ? cidrhost(values.cidr, 0) : values.cidr)[i]) <= tonumber(v) &&
76-
tonumber(split(".", strcontains(values.cidr, "/") ? cidrhost(values.cidr, -1) : values.cidr)[i]) >= tonumber(v)
77-
])
78-
],
79-
0),
80-
"")
59+
bastion_tags = distinct(concat(var.bastion_tags, [
60+
for rule, values in var.firewall_rules :
61+
values.tag
62+
if values.ethertype == "IPv4" &&
63+
22 <= values.from_port && values.to_port <= 22 &&
64+
alltrue([
65+
for i, v in split(".", local.agent_ip) :
66+
tonumber(split(".", strcontains(values.cidr, "/") ? cidrhost(values.cidr, 0) : values.cidr)[i]) <= tonumber(v) &&
67+
tonumber(split(".", strcontains(values.cidr, "/") ? cidrhost(values.cidr, -1) : values.cidr)[i]) >= tonumber(v)
68+
])
69+
]))
8170
}
8271

8372
check "disk_space_per_tag" {

common/design/outputs.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ output "domain_name" {
1818
value = local.domain_name
1919
}
2020

21-
output "bastion_tag" {
22-
value = local.bastion_tag
21+
output "bastion_tags" {
22+
value = local.bastion_tags
2323
}

common/design/variables.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ variable "pool" {}
66
variable "firewall_rules" {}
77
variable "min_disk_size" {}
88
variable "image" {}
9+
variable "bastion_tags" {}

common/provision/main.tf

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
variable "configuration" {}
1+
variable "configuration" {
2+
validation {
3+
condition = length(var.configuration.bastions) > 0
4+
error_message = "Firewall rules do not allow Terraform to SSH to at least one instance."
5+
}
6+
}
27
variable "hieradata" {}
38
variable "hieradata_dir" {}
49
variable "eyaml_key" {}
@@ -54,13 +59,17 @@ data "archive_file" "puppetserver_files" {
5459
}
5560
}
5661

62+
locals {
63+
bastion_host = length(var.configuration.bastions) > 0 ? var.configuration.bastions[keys(var.configuration.bastions)[0]] : null
64+
}
65+
5766
resource "terraform_data" "deploy_puppetserver_files" {
58-
for_each = length(var.configuration.bastions) > 0 ? var.configuration.puppetservers : {}
67+
for_each = local.bastion_host != null ? var.configuration.puppetservers : {}
5968

6069
connection {
6170
type = "ssh"
6271
agent = false
63-
bastion_host = var.configuration.bastions[keys(var.configuration.bastions)[0]].public_ip
72+
bastion_host = contains(local.bastion_host.tags, "public") ? local.bastion_host.public_ip : local.bastion_host.local_ip
6473
bastion_user = "tf"
6574
bastion_private_key = var.configuration.ssh_key.private
6675
user = "tf"

common/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,9 @@ variable "eyaml_key" {
169169
error_message = "Unsupported private key format"
170170
}
171171
}
172+
173+
variable "bastion_tags" {
174+
type = list(string)
175+
default = []
176+
description = "Tags identifying instances that can be used by Terraform as the first hop to transfer files to the Puppet server."
177+
}

docs/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,16 @@ install complementary modules with [r10k](https://github.com/puppetlabs/r10k).
964964
**Post build modification effect**: trigger scp of Puppetfile at next `terraform apply`.
965965
Each instance's Puppet agent will be reloaded following the installation of the new modules.
966966
967+
### 4.22 bastion_tags (optional)
968+
969+
**default_value** = `[]`
970+
971+
Defines a list of tags identifying instances that can be used by Terraform as the first hop
972+
to transfer files to the Puppet server. By default, this list is infered from the list of
973+
[firewall rules](#416-firewall_rules-optional) and the public ip address of the agent calling
974+
`terraform apply`. Providing an explicit list of tags allow to bypass the firewall rule inference,
975+
which can be useful when the agent is in the same network as the cluster.
976+
967977
## 5. Cloud Specific Configuration
968978
969979
### 5.1 Amazon Web Services

examples/incus/main.tf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@ module "incus" {
1313

1414
instances = {
1515
mgmt = { type = "container", cpus = 4, ram = 6000, gpus = 0, tags = ["puppet", "mgmt", "nfs"], count = 1 }
16-
login = { type = "container", cpus = 2, ram = 3000, gpus = 0, tags = ["login", "public", "proxy"], count = 1 }
16+
login = { type = "container", cpus = 2, ram = 3000, gpus = 0, tags = ["login", "proxy"], count = 1 }
1717
node = { type = "container", cpus = 2, ram = 3000, gpus = 0, tags = ["node"], count = 1 }
1818
}
1919

20+
firewall_rules = {
21+
http = { "from_port" = 80, "to_port" = 80, tag = "proxy", "cidr" = "0.0.0.0/0" },
22+
https = { "from_port" = 443, "to_port" = 443, tag = "proxy", "cidr" = "0.0.0.0/0" },
23+
}
24+
bastion_tags = ["login"]
25+
2026
volumes = {}
2127

2228
public_keys = []

0 commit comments

Comments
 (0)