Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
159 changes: 159 additions & 0 deletions .github/workflows/pull_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,162 @@ jobs:
VERSION: ${{ github.ref_name }}
run: |
make build-rancher

terraform:
name: 'Terraform'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install-nix
run: |
curl -L https://nixos.org/nix/install | sh
source /home/runner/.nix-profile/etc/profile.d/nix.sh
nix --version
which nix
- name: lint terraform
shell: /home/runner/.nix-profile/bin/nix develop --ignore-environment --extra-experimental-features nix-command --extra-experimental-features flakes --keep HOME --keep SSH_AUTH_SOCK --keep GITHUB_TOKEN --keep AWS_ROLE --keep AWS_REGION --keep AWS_DEFAULT_REGION --keep AWS_ACCESS_KEY_ID --keep AWS_SECRET_ACCESS_KEY --keep AWS_SESSION_TOKEN --keep UPDATECLI_GPGTOKEN --keep UPDATECLI_GITHUB_TOKEN --keep UPDATECLI_GITHUB_ACTOR --keep GPG_SIGNING_KEY --keep NIX_SSL_CERT_FILE --keep NIX_ENV_LOADED --keep TERM --command bash -e {0}
run: |
terraform fmt -check -recursive
tflint --recursive

actionlint:
name: 'Lint Workflows'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install-nix
run: |
curl -L https://nixos.org/nix/install | sh
source /home/runner/.nix-profile/etc/profile.d/nix.sh
nix --version
which nix
- name: action lint
shell: /home/runner/.nix-profile/bin/nix develop --ignore-environment --extra-experimental-features nix-command --extra-experimental-features flakes --keep HOME --keep SSH_AUTH_SOCK --keep GITHUB_TOKEN --keep AWS_ROLE --keep AWS_REGION --keep AWS_DEFAULT_REGION --keep AWS_ACCESS_KEY_ID --keep AWS_SECRET_ACCESS_KEY --keep AWS_SESSION_TOKEN --keep UPDATECLI_GPGTOKEN --keep UPDATECLI_GITHUB_TOKEN --keep UPDATECLI_GITHUB_ACTOR --keep GPG_SIGNING_KEY --keep NIX_SSL_CERT_FILE --keep NIX_ENV_LOADED --keep TERM --command bash -e {0}
run: actionlint

shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install-nix
run: |
curl -L https://nixos.org/nix/install | sh
source /home/runner/.nix-profile/etc/profile.d/nix.sh
nix --version
which nix
- name: shell check
shell: /home/runner/.nix-profile/bin/nix develop --ignore-environment --extra-experimental-features nix-command --extra-experimental-features flakes --keep HOME --keep SSH_AUTH_SOCK --keep GITHUB_TOKEN --keep AWS_ROLE --keep AWS_REGION --keep AWS_DEFAULT_REGION --keep AWS_ACCESS_KEY_ID --keep AWS_SECRET_ACCESS_KEY --keep AWS_SESSION_TOKEN --keep UPDATECLI_GPGTOKEN --keep UPDATECLI_GITHUB_TOKEN --keep UPDATECLI_GITHUB_ACTOR --keep GPG_SIGNING_KEY --keep NIX_SSL_CERT_FILE --keep NIX_ENV_LOADED --keep TERM --command bash -e {0}
run: |
# while read -r file; do
# echo "checking $file..."
# shellcheck -x "$file"
# done <<<"$(grep -Rl -e '^#!' | grep -v '.terraform'| grep -v '.git')"
# in the future run this on every script, but first we need to eliminate unused scripts
shellcheck -x "./scripts/run_tests.sh"

validate-commit-message:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # fetch all history so that we can validate the commit messages
- name: install-nix
run: |
curl -L https://nixos.org/nix/install | sh
source /home/runner/.nix-profile/etc/profile.d/nix.sh
nix --version
which nix
- name: Check commit message
shell: /home/runner/.nix-profile/bin/nix develop --ignore-environment --extra-experimental-features nix-command --extra-experimental-features flakes --keep HOME --keep SSH_AUTH_SOCK --keep GITHUB_TOKEN --keep AWS_ROLE --keep AWS_REGION --keep AWS_DEFAULT_REGION --keep AWS_ACCESS_KEY_ID --keep AWS_SECRET_ACCESS_KEY --keep AWS_SESSION_TOKEN --keep UPDATECLI_GPGTOKEN --keep UPDATECLI_GITHUB_TOKEN --keep UPDATECLI_GITHUB_ACTOR --keep GPG_SIGNING_KEY --keep NIX_SSL_CERT_FILE --keep NIX_ENV_LOADED --keep TERM --command bash -e {0}
run: |
set -e
# Check commit messages
# This steps enforces https://www.conventionalcommits.org/en/v1.0.0/
# This format enables automatic generation of changelogs and versioning
filter() {
COMMIT="$1"
ouput="$(echo "$COMMIT" | grep -e '^fix: ' -e '^feature: ' -e '^feat: ' -e 'refactor!: ' -e 'feature!: ' -e 'feat!: ' -e '^chore(main): ')"
echo "$output"
}
prefix_check() {
message="$1"
if [ "" != "$(filter "$message")" ]; then
echo "...Commit message does not start with the required prefix.
Please use one of the following prefixes: "fix:", "feature:", "feat:", "refactor!:", "feature!:", or "feat!:".
This enables release-please to automatically determine the type of release (major, minor, patch) based on the commit message.
$message"
exit 1
else
echo "...Commit message starts with the required prefix."
fi
}
empty_check() {
message="$1"
if [ "" == "$message" ]; then
echo "...Empty commit message."
exit 1
else
echo "...Commit message isnt empty."
fi
}
length_check() {
message="$1"
if [ "$(wc -m <<<"$message")" -gt 50 ]; then
echo "...Commit message subject line should be less than 50 characters, found $(wc -m "$message")."
exit 1
else
echo "...Commit message subject line is less than 50 characters."
fi
}
spell_check() {
message="$1"
WORDS="$(aspell list <<<"$message")"
if [ "" != "$WORDS" ]; then
echo "...Commit message contains spelling errors on: ^$WORDS\$"
echo "...Also try updating the PR title."
exit 1
else
echo "...Commit message doesnt contain spelling errors."
fi
}

# Fetch the commit messages

COMMIT_MESSAGES="$(gh pr view ${{github.event.number}} --json commits | jq -r '.commits[].messageHeadline')"
echo "Commit messages found: "
echo "$COMMIT_MESSAGES"

while read -r message; do
echo "checking message ^$message\$"
prefix_check "$message"
empty_check "$message"
length_check "$message"
spell_check "$message"
echo "message ^$message\$ passed all checks"
done <<<"$COMMIT_MESSAGES"

gitleaks:
name: 'Scan for Secrets'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install-nix
run: |
curl -L https://nixos.org/nix/install | sh
source /home/runner/.nix-profile/etc/profile.d/nix.sh
nix --version
which nix
- name: Check for secrets
shell: /home/runner/.nix-profile/bin/nix develop --ignore-environment --extra-experimental-features nix-command --extra-experimental-features flakes --keep HOME --keep SSH_AUTH_SOCK --keep GITHUB_TOKEN --keep AWS_ROLE --keep AWS_REGION --keep AWS_DEFAULT_REGION --keep AWS_ACCESS_KEY_ID --keep AWS_SECRET_ACCESS_KEY --keep AWS_SESSION_TOKEN --keep UPDATECLI_GPGTOKEN --keep UPDATECLI_GITHUB_TOKEN --keep UPDATECLI_GITHUB_ACTOR --keep GPG_SIGNING_KEY --keep NIX_SSL_CERT_FILE --keep NIX_ENV_LOADED --keep TERM --command bash -e {0}
run: |
gitleaks detect --no-banner -v --no-git
gitleaks detect --no-banner -v
continue-on-error: true
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ jobs:
echo '${{ env.GPG_PASSPHRASE }}' | gpg --detach-sig --pinentry-mode loopback --passphrase-fd 0 --output "${SHASUM_FILE}.sig" --sign "${SHASUM_FILE}"

echo "Validating signature..."
gpg --verify "${SHASUM_FILE}.sig" "${SHASUM_FILE}"
if [ $? -eq 0 ]; then

if ! gpg --verify "${SHASUM_FILE}.sig" "${SHASUM_FILE}"; then
Comment thread
matttrach marked this conversation as resolved.
echo "Signature is valid..."
else
echo "Signature verification failed!"
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ test/data
.terraform.lock.hcl
*/.terraform.lock.hcl
.terraform
*/*.test
examples/**/rke2
terraform.tfstate
*.tfstate.*
tf-*
*.env
53 changes: 53 additions & 0 deletions examples/deploy_rke2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Deploy RKE2

This example module configures Rancher to deploy a downstream RKE2 cluster.

## Deploy Rancher

This module starts by using the rancher-aws module to deploy Rancher on AWS.

## Downstream

This module has a local module that provides a logical separation for deploying a downstream cluster using the rancher2_cluster_v2 resource.

## Machine Config Patch

There is a local exec that runs kubectl to patch the Amazonec2Config objects.
The AWS access key id and secret access key attributes are obfuscated and unable to be set directly in favor of the Amazonec2Credential object.
The Amazonec2Credential object doesn't support a session token making it impossible to use temporary credentials.
Our CI must use temporary AWS credentials supplied via OIDC, so this may be something that you eliminate from the example in your implementation.
We bypass the Amazonec2Credential object by manually patching the Amazonec2Config objects with the aws_access_key_id and aws_secret_access_key.
The AWS session token isn't obfuscated and is available as an argument when creating a rancher2_machine_config_v2 resource.

## Dependencies

The Flake.nix in the root of the module explains all of the dependencies for the development of the module, it also includes the dependencies to run it.
You can see the list on lines 50-80, but a more specific list is below (with explanations).
- bash -> born again shell with linux core utils
- git -> required by Terraform
- curl -> required by Terraform as well as dependent modules (when downloading RKE2 for install)
- openssh -> required by Terraform and used in dependent modules to connect to servers for initial configuration
- ssh-agent -> used for connecting to remote server for initial configuration, you need to have the key you send into the module loaded in your agent
- gh -> the github cli tool, used to find releases when downloading RKE2 for install
- jq -> json parsing tool, used in dependent modules to parse submodule outputs
- openssl -> required by Terraform and used in dependent modules to verify TLS certificates
- kubectl -> used in local exec to patch kubernetes objects
- awscli2 -> the aws cli tool, used in some dependent modules in some use cases (dualstack)
- tfswitch -> handy for installing Terraform
- yq -> yaml parsing tool, used in dependent modules to parse kubectl outputs
- go -> necessary to run tests

## Environment Variables

I like to set my AWS credentials in environment variables:
- AWS_ROLE -> role to assume when using OIDC
- AWS_REGION -> AWS region to deploy to, make sure there are multiple availability zones when needing HA
- AWS_DEFAULT_REGION -> same as region
- AWS_ACCESS_KEY_ID -> access key, this will make it into the state, please secure it properly
- AWS_SECRET_ACCESS_KEY -> secret key, this will make it into the state, please secure it properly
- AWS_SESSION_TOKEN -> used with temporary AWS credentials, this will make it into the state, please secure it properly
- TF_VAR_aws_access_key_id -> access key, this will make it into the state, please secure it properly
- TF_VAR_aws_secret_access_key -> secret key, this will make it into the state, please secure it properly
- TF_VAR_aws_session_token -> used with temporary AWS credentials, this will make it into the state, please secure it properly
- TF_VAR_aws_region -> AWS region to deploy to, make sure there are multiple availability zones when needing HA

145 changes: 145 additions & 0 deletions examples/deploy_rke2/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
provider "aws" {
default_tags {
tags = {
Id = local.identifier
Owner = local.owner
}
}
region = local.aws_region
}

provider "acme" {
server_url = "${local.acme_server_url}/directory"
}

provider "github" {}
provider "kubernetes" {} # make sure you set the env variable KUBE_CONFIG_PATH to local_file_path (file_path variable)
provider "helm" {} # make sure you set the env variable KUBE_CONFIG_PATH to local_file_path (file_path variable)

provider "rancher2" {
api_url = "https://${local.domain}.${local.zone}"
token_key = module.rancher.admin_token
timeout = "300s"
}

locals {
identifier = var.identifier
example = "downstream"
project_name = "tf-${substr(md5(join("-", [local.example, local.identifier])), 0, 5)}"
username = local.project_name
domain = local.project_name
zone = var.zone
key_name = var.key_name
key = var.key
owner = var.owner
rke2_version = var.rke2_version
local_file_path = var.file_path
runner_ip = chomp(data.http.myip.response_body) # "runner" is the server running Terraform
rancher_version = var.rancher_version
cert_manager_version = "1.16.3" #"1.13.1"
os = "sle-micro-61"
aws_access_key_id = var.aws_access_key_id
aws_secret_access_key = var.aws_secret_access_key
aws_region = var.aws_region
aws_session_token = var.aws_session_token
aws_instance_type = "m5.large"
node_count = 3
email = (var.email != "" ? var.email : "${local.identifier}@${local.zone}")
acme_server_url = "https://acme-v02.api.letsencrypt.org"
}

data "http" "myip" {
url = "https://ipinfo.io/ip"
}

module "rancher" {
source = "rancher/aws/rancher2"
version = "1.2.2"
# project
identifier = local.identifier
owner = local.owner
project_name = local.project_name
domain = local.domain
zone = local.zone
skip_project_cert_generation = true
# access
key_name = local.key_name
key = local.key
username = local.username
admin_ip = local.runner_ip
# rke2
rke2_version = local.rke2_version
local_file_path = local.local_file_path
install_method = "rpm" # rpm only for now, need to figure out local helm chart installs otherwise
cni = "canal"
node_configuration = {
"rancher" = {
type = "all-in-one"
size = "large"
os = local.os
indirect_access = true
initial = true
}
}
# rancher
rancher_version = local.rancher_version
cert_manager_version = local.cert_manager_version
configure_cert_manager = true
cert_manager_configuration = {
aws_access_key_id = local.aws_access_key_id
aws_secret_access_key = local.aws_secret_access_key
aws_session_token = local.aws_session_token
aws_region = local.aws_region
acme_email = local.email
acme_server_url = local.acme_server_url
}
}

module "rke2_image" {
source = "rancher/server/aws"
version = "v1.4.0"
server_use_strategy = "skip"
image_use_strategy = "find"
image_type = local.os # this is not required to match Rancher, it just seemed easier in this example
}

# you can add this one multiple times, or use a loop to deploy multiple clusters
module "downstream" {
depends_on = [
module.rancher,
module.rke2_image,
]
source = "./modules/downstream"
# general
name = "${local.project_name}-aio"
identifier = local.identifier
owner = local.owner
# aws access
aws_access_key_id = local.aws_access_key_id
aws_secret_access_key = local.aws_secret_access_key
aws_session_token = trimspace(chomp(local.aws_session_token))
aws_region = local.aws_region
aws_region_letter = replace(
module.rancher.subnets[keys(module.rancher.subnets)[0]].availability_zone,
local.aws_region,
""
)
# aws project info
vpc_id = module.rancher.vpc.id
security_group_id = module.rancher.security_group.id
load_balancer_security_groups = module.rancher.load_balancer_security_groups
subnet_id = module.rancher.subnets[keys(module.rancher.subnets)[0]].id
# node info
aws_instance_type = local.aws_instance_type
ami_id = module.rke2_image.image.id
ami_ssh_user = module.rke2_image.image.user
ami_admin_group = module.rke2_image.image.admin_group
node_count = local.node_count
direct_node_access = {
runner_ip = local.runner_ip
ssh_access_key = local.key
ssh_access_user = local.project_name
}
# rke2 info
rke2_version = local.rke2_version
}
Loading
Loading