From bd65ca94f138314fbd0fac1afa630bdf035c5b82 Mon Sep 17 00:00:00 2001 From: Matt Trachier Date: Mon, 5 May 2025 10:22:06 -0500 Subject: [PATCH] fix: add direct to project (#118) * fix: cross link direct access --------- Signed-off-by: matttrach --- .envrc | 67 ++++++++++++++++++++---------- .gitignore | 1 + flake.lock | 12 +++--- flake.nix | 2 + main.tf | 1 + modules/direct_access/main.tf | 59 +++++++++++++++++++++----- modules/direct_access/variables.tf | 8 ++++ run_tests.sh | 52 ++++++++++++++++++----- 8 files changed, 154 insertions(+), 48 deletions(-) diff --git a/.envrc b/.envrc index 3078066..7528c4b 100644 --- a/.envrc +++ b/.envrc @@ -1,26 +1,48 @@ #!/bin/env sh +nf () { + nix --extra-experimental-features nix-command --extra-experimental-features flakes "$@" +} + +get_repo_basename() { + basename "$(git rev-parse --show-toplevel)" +} + +get_profile() { + basename="$(get_repo_basename)" + echo "$HOME/.config/nix/profiles/$basename" +} + cleanup() { echo "Cleaning Up..." - - echo 'Getting Nix Usage...' - echo "Nix store is using $(du -hs /nix/store)" - - echo 'Archiving Nix Profile...' - nix develop --profile /tmp/terraform-aws-server-nix-env --extra-experimental-features nix-command --extra-experimental-features flakes --command bash -c "echo done" + basename="$(get_repo_basename)" + profile="$(get_profile)" + if [ -z "$basename" ]; then echo "basename is empty"; exit 1; fi + export NIX_PATH="$profile" + export NIX_PROFILE="$profile" + nix-env --profile "$profile" --delete-generations +3 + nix-env --profile "$profile" --list-generations } if ! which "$0" | grep -q nix; then - print 'Entering Environment...' + print 'Entering Environment...' + basename="$(get_repo_basename)" + profile="$(get_profile)" + export NIX_PROFILE="$profile" print 'Updating Nix Cache...' - nix flake update --extra-experimental-features nix-command --extra-experimental-features flakes + nf flake update + + echo 'Installing Nix Profile...' + nf profile install . --profile "$profile" + nf profile list --profile "$profile" print 'Starting...' - nix develop \ + # --impure allows Nix to reuse previously built paths + # --ignore-environment ignores the environment variables and paths to tools not installed by nix + nf develop \ --ignore-environment \ - --extra-experimental-features nix-command \ - --extra-experimental-features flakes \ + --impure \ --keep HOME \ --keep SSH_AUTH_SOCK \ --keep GITHUB_TOKEN \ @@ -30,27 +52,30 @@ if ! which "$0" | grep -q nix; then --keep AWS_ACCESS_KEY_ID \ --keep AWS_SECRET_ACCESS_KEY \ --keep AWS_SESSION_TOKEN \ + --keep KUBE_CONFIG_PATH \ --keep TERM \ --keep XDG_DATA_DIRS \ - /tmp/terraform-aws-server-nix-env \ + --keep NIX_SSL_CERT_FILE \ + --keep NIX_PROFILE \ + --profile "$profile" \ --command bash -c "bash --rcfile .envrc" print 'Exiting Dev Environment...' cleanup else # this is run inside the dev environment so we can make assumptions about what is available - echo 'Setting up dev environment...' + echo 'Setting up dev environment...' - . .functions - . .variables - . .rcs - . .aliases + . .functions + . .variables + . .rcs + . .aliases - if [ -z "$SSH_AUTH_SOCK" ]; then eval "$(ssh-agent -s)"; ssh-add; fi + if [ -z "$SSH_AUTH_SOCK" ]; then eval "$(ssh-agent -s)"; ssh-add; fi - if ! env | grep -q 'AWS'; then - echo 'Unable to find AWS authentication information in the environment, please make sure you authenticate with AWS.' + if ! env | grep -q 'AWS'; then + echo 'Unable to find AWS authentication information in the environment, please make sure you authenticate with AWS.' echo 'Try using the "aws" cli included in the environment.' - fi + fi fi diff --git a/.gitignore b/.gitignore index 2f8e396..d141d6f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ examples/*/50-* *.lock *.DS_* test/data/* +*.test diff --git a/flake.lock b/flake.lock index c0137b3..1142197 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1724395761, - "narHash": "sha256-zRkDV/nbrnp3Y8oCADf5ETl1sDrdmAW6/bBVJ8EbIdQ=", + "lastModified": 1746152631, + "narHash": "sha256-zBuvmL6+CUsk2J8GINpyy8Hs1Zp4PP6iBWSmZ4SCQ/s=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ae815cee91b417be55d43781eb4b73ae1ecc396c", + "rev": "032bc6539bd5f14e9d0c51bd79cfe9a055b094c3", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index feff97e..89d4939 100644 --- a/flake.nix +++ b/flake.nix @@ -58,6 +58,7 @@ gitleaks gnupg go + golint gotestfmt gotestsum jq @@ -72,6 +73,7 @@ updatecli vim which + yq-go ]; }; diff --git a/main.tf b/main.tf index 0c21c3d..a31aad0 100644 --- a/main.tf +++ b/main.tf @@ -173,4 +173,5 @@ module "direct_access" { type = "A" # we will enable ipv6 in the future ips = distinct([module.server[0].public_ip, module.server[0].private_ip]) } + server_security_group_name = local.server_security_group_name } diff --git a/modules/direct_access/main.tf b/modules/direct_access/main.tf index dec207e..a825993 100644 --- a/modules/direct_access/main.tf +++ b/modules/direct_access/main.tf @@ -11,8 +11,34 @@ locals { add_eip = var.add_eip domain_ips = flatten(local.domain.ips) # tflint-ignore: terraform_unused_declarations - fail_domain_ips = ((local.add_domain && length(local.domain_ips) == 0) ? one([local.domain_ips, "missing_domain_ips"]) : false) - all_ips = compact(concat(local.domain_ips, [(local.add_eip ? aws_eip.created[0].public_ip : "")])) + fail_domain_ips = ((local.add_domain && length(local.domain_ips) == 0) ? one([local.domain_ips, "missing_domain_ips"]) : false) + all_ips = compact(concat(local.domain_ips, [(local.add_eip ? aws_eip.created[0].public_ip : "")])) + server_security_group_name = var.server_security_group_name + + access_address_cidrs_length = [ + for i in range(length(local.access_addresses)) : + length(local.access_addresses[keys(local.access_addresses)[i]].cidrs) + ] # [1,1,2,2,1] + + access_address_cidrs_matrix = merge([ + for ia in range(length(local.access_addresses)) : + { + for ib in range(local.access_address_cidrs_length[ia]) : + "${keys(local.access_addresses)[ia]}-${ib}" => { + port = local.access_addresses[keys(local.access_addresses)[ia]].port + cidr = local.access_addresses[keys(local.access_addresses)[ia]].cidrs[ib] + ip_family = local.access_addresses[keys(local.access_addresses)[ia]].ip_family + protocol = local.access_addresses[keys(local.access_addresses)[ia]].protocol + } + } + ]...) +} + +data "aws_security_group" "server_security_group" { + filter { + name = "tag:Name" + values = [local.server_security_group_name] + } } resource "aws_security_group" "direct_access" { @@ -24,18 +50,28 @@ resource "aws_security_group" "direct_access" { } } -resource "aws_security_group_rule" "server_ingress" { +resource "aws_vpc_security_group_ingress_rule" "server_ingress" { depends_on = [ aws_security_group.direct_access, ] - for_each = local.access_addresses + for_each = local.access_address_cidrs_matrix security_group_id = aws_security_group.direct_access.id - type = "ingress" from_port = each.value.port to_port = each.value.port - protocol = each.value.protocol - cidr_blocks = (each.value.ip_family != "ipv6" ? each.value.cidrs : null) - ipv6_cidr_blocks = (each.value.ip_family == "ipv6" ? each.value.cidrs : null) + ip_protocol = each.value.protocol + cidr_ipv4 = (each.value.ip_family != "ipv6" ? each.value.cidr : null) + cidr_ipv6 = (each.value.ip_family == "ipv6" ? each.value.cidr : null) +} + +# allow the server's security group direct access to the server +resource "aws_vpc_security_group_ingress_rule" "server_direct_link" { + depends_on = [ + aws_security_group.direct_access, + data.aws_security_group.server_security_group, + ] + security_group_id = aws_security_group.direct_access.id + referenced_security_group_id = data.aws_security_group.server_security_group.id + ip_protocol = -1 } resource "aws_network_interface_sg_attachment" "server_security_group_attachment" { @@ -46,7 +82,6 @@ resource "aws_network_interface_sg_attachment" "server_security_group_attachment network_interface_id = local.server.network_interface_id } - resource "aws_eip" "created" { count = local.add_eip ? 1 : 0 domain = "vpc" @@ -87,7 +122,8 @@ resource "terraform_data" "setup" { aws_eip.created, aws_eip_association.created, aws_network_interface_sg_attachment.server_security_group_attachment, - aws_security_group_rule.server_ingress, + aws_vpc_security_group_ingress_rule.server_ingress, + aws_vpc_security_group_ingress_rule.server_direct_link, aws_security_group.direct_access, ] count = (local.use_strategy == "ssh" ? 1 : 0) @@ -125,7 +161,8 @@ resource "terraform_data" "remove_initial_user" { terraform_data.setup, aws_eip_association.created, aws_network_interface_sg_attachment.server_security_group_attachment, - aws_security_group_rule.server_ingress, + aws_vpc_security_group_ingress_rule.server_ingress, + aws_vpc_security_group_ingress_rule.server_direct_link, aws_security_group.direct_access, ] count = (local.use_strategy == "ssh" ? 1 : 0) diff --git a/modules/direct_access/variables.tf b/modules/direct_access/variables.tf index 3aad015..b2a7b4e 100644 --- a/modules/direct_access/variables.tf +++ b/modules/direct_access/variables.tf @@ -127,3 +127,11 @@ variable "add_eip" { If set to true, we will add an elastic ip to the instance. EOT } + +variable "server_security_group_name" { + type = string + description = <<-EOT + The name for the security group that the server is on. + We will allow direct access to this security group as well as the cidrs in the access address objects. + EOT +} diff --git a/run_tests.sh b/run_tests.sh index 89f97ab..fca3bf4 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -3,16 +3,30 @@ rerun_failed=false specific_test="" specific_package="" +cleanup_id="" -while getopts ":r:t:p:" opt; do +while getopts ":r:t:p:c:" opt; do case $opt in r) rerun_failed=true ;; t) specific_test="$OPTARG" ;; p) specific_package="$OPTARG" ;; - \?) echo "Invalid option -$OPTARG" >&2 && exit 1 ;; + c) cleanup_id="$OPTARG" ;; + \?) cat <&2 && exit 1 ;; +Invalid option -$OPTARG, valid options are + -r to re-run failed tests + -t to specify a specific test (eg. TestBase) + -p to specify a specific test package (eg. base) + -c to run clean up only with the given id (eg. abc123) +EOT esac done +if [ -n "$cleanup_id" ]; then + export IDENTIFIER="$cleanup_id" +fi + +REPO_ROOT="$(git rev-parse --show-toplevel)" + run_tests() { local rerun=$1 REPO_ROOT="$(git rev-parse --show-toplevel)" @@ -94,13 +108,31 @@ if [ -z "$GITHUB_TOKEN" ]; then echo "GITHUB_TOKEN isn't set"; else echo "GITHUB if [ -z "$GITHUB_OWNER" ]; then echo "GITHUB_OWNER isn't set"; else echo "GITHUB_OWNER is set"; fi if [ -z "$ZONE" ]; then echo "ZONE isn't set"; else echo "ZONE is set"; fi -# Run tests initially -run_tests false +if [ -z "$cleanup_id" ]; then + echo "checking tests for compile errors..." + D="$(pwd)" + cd "$REPO_ROOT/test/tests" || exit + if ! go mod tidy; then echo "failed to tidy, exit code $?"; exit 1; fi -# Check if we need to rerun failed tests -if [ "$rerun_failed" = true ] && [ -f "/tmp/${IDENTIFIER}_failed_tests.txt" ]; then - echo "Rerunning failed tests..." - run_tests true + while IFS= read -r file; do + echo "found $file"; + if ! go test -c "$file"; then C=$?; echo "failed to compile $file, exit code $C"; exit $C; fi + done < "$(find "$REPO_ROOT/test" -name '*.go')" + echo "compile checks passed..." + cd "$D" || exit + + echo "checking terraform configs for errors..." + if ! tflint --recursive; then C=$?; echo "tflint failed, exit code $C"; exit $C; fi + echo "terraform configs valid..." + + # Run tests initially + run_tests false + + # Check if we need to rerun failed tests + if [ "$rerun_failed" = true ] && [ -f "/tmp/${IDENTIFIER}_failed_tests.txt" ]; then + echo "Rerunning failed tests..." + run_tests true + fi fi echo "Clearing leftovers with Id $IDENTIFIER in $AWS_REGION..." @@ -121,8 +153,8 @@ if [ -n "$IDENTIFIER" ]; then attempts=0 # shellcheck disable=SC2143 - while [ -n "$(leftovers -d --iaas=aws --aws-region="$AWS_REGION" --type="ec2-key-pair" --filter="tf-$IDENTIFIER" | grep -v 'AccessDenied')" ] && [ $attempts -lt 3 ]; do - leftovers --iaas=aws --aws-region="$AWS_REGION" --type="ec2-key-pair" --filter="tf-$IDENTIFIER" --no-confirm | grep -v 'AccessDenied' || true + while [ -n "$(leftovers -d --iaas=aws --aws-region="$AWS_REGION" --type="ec2-key-pair" --filter="terraform-ci-$IDENTIFIER" | grep -v 'AccessDenied')" ] && [ $attempts -lt 3 ]; do + leftovers --iaas=aws --aws-region="$AWS_REGION" --type="ec2-key-pair" --filter="terraform-ci-$IDENTIFIER" --no-confirm | grep -v 'AccessDenied' || true sleep 10 attempts=$((attempts + 1)) done