Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to setup provisioner infrastructure with Terraform Cloud #177

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ repos:
language: system
entry: bazel run --config=quiet @aspect_rules_format//format
files: .*
exclude: ^tmp/
- id: terraform_fmt
name: Terraform fmt
description: Rewrites all Terraform configuration files to a canonical format.
entry: bazel run --config=quiet //tools/terraform -- fmt
language: system
files: (\.tf|\.tfvars)$
exclude: \.terraform\/.*$
exclude: (\.terraform\/.*$|^tmp/)
- id: terramate_fmt
name: Terramate fmt
description: Rewrites all Terramate configuration files to a canonical format.
entry: bazel run --config=quiet //tools/terramate -- fmt
language: system
files: (\.tm.hcl)$
pass_filenames: false
exclude: ^tmp/
27 changes: 27 additions & 0 deletions infrastructure/modules/ssh_tunnel/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copied from https://github.com/flaupretre/terraform-ssh-tunnel
resource "random_integer" "ssh_port" {
min = "10000"
max = "60000"
}

data "external" "ssh_tunnel" {
program = [
var.shell_cmd,
"${path.module}/tunnel.sh"
]

query = {
timeout = var.timeout,
ssh_cmd = var.ssh_cmd,
local_host = var.local_host,
local_port = random_integer.ssh_port.result,
target_host = var.target_host,
target_port = var.target_port,
gateway_host = var.gateway_host,
gateway_port = var.gateway_port,
gateway_user = var.gateway_user,
shell_cmd = var.shell_cmd,
ssh_tunnel_check_sleep = var.ssh_tunnel_check_sleep
create = ((var.create && var.putin_khuylo) ? "y" : "")
}
}
9 changes: 9 additions & 0 deletions infrastructure/modules/ssh_tunnel/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "port" {
value = data.external.ssh_tunnel.result.port
description = "Port number to connect to"
}

output "host" {
value = data.external.ssh_tunnel.result.host
description = "Host to connect to"
}
92 changes: 92 additions & 0 deletions infrastructure/modules/ssh_tunnel/tunnel.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
MPID="$1"
ret=0

#---

if [ -z "$MPID" ]; then
if [ -n "$TUNNEL_DEBUG" ]; then
exec 2> /tmp/t1
set -x
env >&2
fi

ABSPATH=$(
cd "$(dirname "$0")"
pwd -P
)

query="$(dd 2> /dev/null)"
[ -n "$TUNNEL_DEBUG" ] && echo "query: <$query>" >&2

export TIMEOUT="$(echo $query | sed -e 's/^.*\"timeout\": *\"//' -e 's/\".*$//g')"
export SSH_CMD="$(echo $query | sed -e 's/^.*\"ssh_cmd\": *\"//' -e 's/\",.*$//g' -e 's/\\\"/\"/g')"
export LOCAL_HOST="$(echo $query | sed -e 's/^.*\"local_host\": *\"//' -e 's/\".*$//g')"
export LOCAL_PORT="$(echo $query | sed -e 's/^.*\"local_port\": *\"//' -e 's/\".*$//g')"
export TARGET_HOST="$(echo $query | sed -e 's/^.*\"target_host\": *\"//' -e 's/\".*$//g')"
export TARGET_PORT="$(echo $query | sed -e 's/^.*\"target_port\": *\"//' -e 's/\".*$//g')"
export GATEWAY_HOST="$(echo $query | sed -e 's/^.*\"gateway_host\": *\"//' -e 's/\".*$//g')"
export GATEWAY_PORT="$(echo $query | sed -e 's/^.*\"gateway_port\": *\"//' -e 's/\".*$//g')"
export GATEWAY_USER="$(echo $query | sed -e 's/^.*\"gateway_user\": *\"//' -e 's/\".*$//g')"
export SHELL_CMD="$(echo $query | sed -e 's/^.*\"shell_cmd\": *\"//' -e 's/\",.*$//g' -e 's/\\\"/\"/g')"
export SSH_TUNNEL_CHECK_SLEEP="$(echo $query | sed -e 's/^.*\"ssh_tunnel_check_sleep\": *\"//' -e 's/\",.*$//g' -e 's/\\\"/\"/g')"
export CREATE="$(echo $query | sed -e 's/^.*\"create\": *\"//' -e 's/\",.*$//g' -e 's/\\\"/\"/g')"

if [ "X$CREATE" = X -o "X$GATEWAY_HOST" = X ]; then
# No tunnel - connect directly to target host
do_tunnel=''
cnx_host="$TARGET_HOST"
cnx_port="$TARGET_PORT"
else
do_tunnel='y'
cnx_host="$LOCAL_HOST"
cnx_port="$LOCAL_PORT"
fi

echo "{ \"host\": \"$cnx_host\", \"port\": \"$cnx_port\" }"

if [ -n "$do_tunnel" ]; then
p=$(ps -p $PPID -o "ppid=")
clog=$(mktemp)
nohup timeout $TIMEOUT $SHELL_CMD "$ABSPATH/tunnel.sh" $p <&- >&- 2> $clog &
CPID=$!
# A little time for the SSH tunnel process to start or fail
sleep 3
# If the child process does not exist anymore after this delay, report failure
if ! ps -p $CPID > /dev/null 2>&1; then
echo "Child process ($CPID) failure - Aborting" >&2
echo "Child diagnostics follow:" >&2
cat $clog >&2
rm -f $clog
ret=1
fi
rm -f $clog
fi
else
#------ Child
if [ -n "$TUNNEL_DEBUG" ]; then
exec 2> /tmp/t2
set -x
env >&2
fi

gw="$GATEWAY_HOST"
[ "X$GATEWAY_USER" = X ] || gw="$GATEWAY_USER@$GATEWAY_HOST"

$SSH_CMD -vvvv -N -L $LOCAL_HOST:$LOCAL_PORT:$TARGET_HOST:$TARGET_PORT -p $GATEWAY_PORT $gw &
CPID=$!

sleep $SSH_TUNNEL_CHECK_SLEEP

while true; do
if ! ps -p $CPID > /dev/null 2>&1; then
echo "SSH process ($CPID) failure - Aborting" >&2
exit 1
fi
ps -p $MPID > /dev/null 2>&1 || break
sleep 1
done

kill $CPID
fi

exit $ret
69 changes: 69 additions & 0 deletions infrastructure/modules/ssh_tunnel/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
variable "create" {
type = bool
description = "If false, do nothing and return target host"
default = true
}

variable "shell_cmd" {
type = string
description = "Command to run a shell"
default = "bash"
}

variable "ssh_cmd" {
type = string
description = "Shell command to use to start ssh client"
default = "ssh -o StrictHostKeyChecking=no"
}

variable "local_host" {
type = string
description = "Local host name or IP. Set only if you cannot use the '127.0.0.1' default value"
default = "127.0.0.1"
}

variable "target_host" {
type = string
description = "The target host. Name will be resolved by gateway"
}

variable "target_port" {
type = number
description = "Target port number"
}

variable "gateway_host" {
type = any
default = ""
description = "Name or IP of SSH gateway - empty string if no gateway (direct connection)"
}

variable "gateway_user" {
type = any
description = "User to use on SSH gateway (default = empty string = current username)"
default = ""
}

variable "gateway_port" {
type = number
description = "Gateway port"
default = 22
}

variable "timeout" {
type = string
description = "Timeout value ensures tunnel won't remain open forever"
default = "30m"
}

variable "ssh_tunnel_check_sleep" {
type = string
description = "extra time to wait for ssh tunnel to connect"
default = "0s"
}

variable "putin_khuylo" {
description = "Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo!"
type = bool
default = true
}
10 changes: 5 additions & 5 deletions infrastructure/stacks/backend.tm.hcl
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
generate_hcl "_terramate_generated_backend.tf" {
content {
terraform {
cloud {
organization = "home-production"
cloud {
organization = "home-production"

workspaces {
name = global.cloud_workspace_name
}
workspaces {
name = global.cloud_workspace_name
}
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions infrastructure/stacks/base/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 58 additions & 2 deletions infrastructure/stacks/base/_terramate_generated_providers.tf
Original file line number Diff line number Diff line change
@@ -1,19 +1,75 @@
// TERRAMATE: GENERATED AUTOMATICALLY DO NOT EDIT

terraform {
required_version = "1.4.2"
required_version = ">=1.0.0"
required_providers {
helm = {
version = "2.9.0"
}
ssh = {
source = "thecadams/ssh"
version = "0.1.12"
}
tfe = {
version = "0.42.0"
}
}
}
variable "provisioner_private_key" {
description = "Private key of the provisioner machine"
sensitive = true
type = string
}
variable "provisioner_private_key_second" {
description = "Private key of the provisioner machine"
sensitive = true
type = string
}
variable "provisioner_host" {
description = "Host name of the provisioner machine"
sensitive = true
type = string
}
variable "provisioner_port" {
description = "Port number of the provisioner machine"
sensitive = true
type = string
}
locals {
provisioner_private_key_file = abspath("${path.module}/provisioner_private_key")
}
resource "local_sensitive_file" "provisioner_private_key" {
content = var.provisioner_private_key_second
file_permission = "0600"
filename = local.provisioner_private_key_file
}
module "kubernetes_tunnel" {
depends_on = [
local_sensitive_file.provisioner_private_key,
]
gateway_host = var.provisioner_host
gateway_port = var.provisioner_port
gateway_user = "ubuntu"
source = "../../modules/ssh_tunnel"
ssh_cmd = "ssh -o StrictHostKeyChecking=no -i ${local.provisioner_private_key_file}"
ssh_tunnel_check_sleep = "10s"
target_host = "192.168.1.31"
target_port = 16443
}
variable "provisioner_kube_config" {
description = "Kube config of the provisioner machine"
sensitive = true
type = string
}
locals {
provisioner_kube_config = yamldecode(var.provisioner_kube_config)
}
provider "helm" {
alias = "provisioner"
kubernetes {
config_path = "../../../tmp/provisioner_kube_config"
cluster_ca_certificate = base64decode(local.provisioner_kube_config.clusters[0].cluster.certificate-authority-data)
host = "https://${module.kubernetes_tunnel.host}:${module.kubernetes_tunnel.port}"
token = local.provisioner_kube_config.users[0].user.token
}
}
provider "tfe" {
Expand Down
11 changes: 10 additions & 1 deletion infrastructure/stacks/base/main.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
resource "tfe_workspace" "provisioner" {
name = var.provisioner_workspace_name
organization = "home-production"
execution_mode = "local"
execution_mode = "remote"
}

module "ssh_tunnel" {
source = "../../modules/ssh_tunnel"

target_host = var.provisioner_host
target_port = 22

# gateway_host = data.aws_instances.bastions.public_ips[0]
}
3 changes: 3 additions & 0 deletions infrastructure/stacks/base/stack.tm.hcl
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
stack {
name = "base"
tags = [
"base",
]
}

globals {
Expand Down
4 changes: 4 additions & 0 deletions infrastructure/stacks/base/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
variable "provisioner_host" {
type = string
description = "Host name of the provisioner machine"
}
Loading