diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index edba90a..a3d2335 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -1,5 +1,6 @@ name: Build and Push Docker Image to Docker Hub on: + pull_request: push: branches: [ "main" ] tags: @@ -12,11 +13,17 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 + with: + driver: docker-container - name: Log in to Docker Hub + if: github.event_name == 'push' uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} @@ -26,6 +33,9 @@ jobs: uses: docker/build-push-action@v4 with: context: . - push: true - tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest platforms: linux/amd64,linux/arm64 + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + # Pull requests must produce the required "build" check without + # publishing. Multi-arch builds cannot be loaded into the local + # Docker engine, so they are cached only until a main/tag push. + outputs: ${{ github.event_name == 'push' && 'type=registry' || 'type=cacheonly' }} diff --git a/Dockerfile b/Dockerfile index 0a4e7af..a922284 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,46 +1,54 @@ FROM ubuntu:20.04 -ENV NVM_DIR /usr/local/nvm +ENV NVM_DIR=/usr/local/nvm -# Install all dependencies, NVM, GitHub CLI, and other tools in a single RUN command +# Install dependencies, AWS CLI, kubectl, Helm, tfenv, NVM, and GitHub CLI. +# Node itself is installed at runtime by script.sh when NODE_VERSION is set. RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ - git \ - jq \ - unzip \ - curl \ - wget \ - tar \ - openssl \ - python3 \ - python3-pip \ - && curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \ + git \ + jq \ + unzip \ + curl \ + wget \ + tar \ + openssl \ + python3 \ + python3-pip \ + && arch=$(dpkg --print-architecture) \ + && case "$arch" in \ + amd64) aws_cli_url="https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"; kubectl_arch="amd64" ;; \ + arm64) aws_cli_url="https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip"; kubectl_arch="arm64" ;; \ + *) echo "Unsupported architecture: $arch" >&2; exit 1 ;; \ + esac \ + && curl -fsSL "$aws_cli_url" -o awscliv2.zip \ && unzip awscliv2.zip \ && ./aws/install \ - && curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \ + && curl -fsSL -o kubectl "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/${kubectl_arch}/kubectl" \ && install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl \ && curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 \ && chmod 700 get_helm.sh \ && ./get_helm.sh \ - && git clone https://github.com/tfutils/tfenv.git ~/.tfenv \ + && git clone https://github.com/tfutils/tfenv.git /root/.tfenv \ && pip3 install urllib3==1.26.7 print-env \ - && mkdir -p $NVM_DIR \ - && curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash \ - && . $NVM_DIR/nvm.sh \ - # Install GitHub CLI - && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ - && apt update \ - && apt install gh \ - # Clean up + && mkdir -p "$NVM_DIR" \ + && curl -fsSL -o /tmp/nvm-install.sh https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh \ + && bash /tmp/nvm-install.sh \ + && rm /tmp/nvm-install.sh \ + && curl -fsSL -o /usr/share/keyrings/githubcli-archive-keyring.gpg https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y gh \ && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /awscliv2.zip + && rm -rf /var/lib/apt/lists/* awscliv2.zip aws kubectl get_helm.sh -# Set environment path for tfenv and NVM -ENV PATH="/root/.tfenv/bin:$NVM_DIR/versions/node/$(nvm version)/bin:$PATH" +# tfenv is a real binary path. nvm is a shell function loaded by script.sh, +# so a node version directory cannot be added here. +ENV PATH="/root/.tfenv/bin:$PATH" -# Create and set the working directory WORKDIR /work -# Copy the script into the container COPY ./script.sh / -RUN chmod u+x /script.sh +COPY ./mfa.sh /usr/local/bin/mfa.sh +COPY ./aws-role-credentials /usr/local/bin/aws-role-credentials +RUN chmod u+x /script.sh /usr/local/bin/mfa.sh /usr/local/bin/aws-role-credentials \ + && printf '\nmfa() { source /usr/local/bin/mfa.sh "$@"; }\n' >> /root/.bashrc diff --git a/Readme.md b/Readme.md index e2255fd..ec61c95 100644 --- a/Readme.md +++ b/Readme.md @@ -42,3 +42,21 @@ Notes: ```bash dev ``` + +## AWS role + +If the Portunus project has `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_ROLE_TO_ASSUME`, the container assumes that role before the shell opens and prints the role and session expiry. The IAM user keys are not put in the environment or the default AWS profile. Commands use the assumed role, and if that role cannot be assumed the command fails instead of running as the IAM user. The AWS CLI assumes the role again after the session expires. + +`dev` with no project does not load Portunus, so that container does not assume a role. Keys without `AWS_ROLE_TO_ASSUME` still configure the default profile as the IAM user. + +## AWS MFA + +Inside the container, after AWS credentials are configured: + +```bash +mfa 123456 +``` + +`123456` is the code from your authenticator app. That command sources `/usr/local/bin/mfa.sh`, writes a session token to `~/.aws/credentials`, and exports `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` in the current shell. + +`source ./mfa.sh` does not work here. `dev` mounts the project on `/work`, so a script copied into the project is hidden or left behind in that repository. `mfa` stays in the image, outside that mount. diff --git a/aws-role-credentials b/aws-role-credentials new file mode 100755 index 0000000..d91aa43 --- /dev/null +++ b/aws-role-credentials @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# credential_process for the default AWS profile. +# Prints assumed-role credentials, or exits non-zero. It never prints the IAM user keys. +set -euo pipefail + +key_file="${HOME}/.aws/role-source.json" +if [ ! -f "$key_file" ]; then + echo "Missing ${key_file}" >&2 + exit 1 +fi + +role_arn=$(jq -er '.RoleArn // empty' "$key_file") +access_key_id=$(jq -er '.AccessKeyId // empty' "$key_file") +secret_access_key=$(jq -er '.SecretAccessKey // empty' "$key_file") +session_token=$(jq -r '.SessionToken // empty' "$key_file") +if [ -z "$role_arn" ] || [ -z "$access_key_id" ] || [ -z "$secret_access_key" ]; then + echo "Role source file is incomplete" >&2 + exit 1 +fi + +# The user keys are passed only to this AssumeRole call. Clearing the config +# and profile variables stops this aws process from calling itself. +sts_json=$( + unset AWS_PROFILE AWS_DEFAULT_PROFILE AWS_CONFIG_FILE AWS_SHARED_CREDENTIALS_FILE \ + AWS_CONTAINER_CREDENTIALS_RELATIVE_URI AWS_CONTAINER_CREDENTIALS_FULL_URI \ + AWS_WEB_IDENTITY_TOKEN_FILE AWS_ROLE_ARN + export AWS_ACCESS_KEY_ID="$access_key_id" + export AWS_SECRET_ACCESS_KEY="$secret_access_key" + if [ -n "$session_token" ]; then + export AWS_SESSION_TOKEN="$session_token" + else + unset AWS_SESSION_TOKEN + fi + aws sts assume-role \ + --role-arn "$role_arn" \ + --role-session-name docker-dev-env \ + --output json +) + +expiry=$(jq -er '.Credentials.Expiration // empty' <<<"$sts_json") +access_key_out=$(jq -er '.Credentials.AccessKeyId // empty' <<<"$sts_json") +secret_out=$(jq -er '.Credentials.SecretAccessKey // empty' <<<"$sts_json") +token_out=$(jq -er '.Credentials.SessionToken // empty' <<<"$sts_json") +if [ -z "$expiry" ] || [ -z "$access_key_out" ] || [ -z "$secret_out" ] || [ -z "$token_out" ]; then + echo "AssumeRole response was incomplete" >&2 + exit 1 +fi + +printf '%s\n' "$expiry" > "${HOME}/.aws/role-expiration" +chmod 600 "${HOME}/.aws/role-expiration" + +jq -nc \ + --arg AccessKeyId "$access_key_out" \ + --arg SecretAccessKey "$secret_out" \ + --arg SessionToken "$token_out" \ + --arg Expiration "$expiry" \ + '{Version: 1, AccessKeyId: $AccessKeyId, SecretAccessKey: $SecretAccessKey, SessionToken: $SessionToken, Expiration: $Expiration}' diff --git a/mfa.sh b/mfa.sh new file mode 100644 index 0000000..4694293 --- /dev/null +++ b/mfa.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env bash +# Temporary AWS credentials from an MFA code. +# +# Source this file so the new credentials stay in the current shell. +# The container shell provides `mfa` for that: +# mfa 123456 +# source /usr/local/bin/mfa.sh 123456 +# +# Running this file as a program cannot update the shell you are already in. + +if [ -z "${1:-}" ]; then + echo "Usage: mfa " >&2 + return 1 2>/dev/null || exit 1 +fi + +session_duration=129600 # 36 hours, the STS maximum for GetSessionToken +mfa_code=$1 +aws_dir="${HOME}/.aws" +aws_creds_file="${aws_dir}/credentials" +orig_creds_file="${aws_dir}/origcreds" +tmp_creds_file="${aws_dir}/tempcreds" +role_source_file="${aws_dir}/role-source.json" +role_source_orig_file="${aws_dir}/role-source-orig.json" + +# A configured role must stay the only identity used for commands. MFA refreshes +# the keys that call AssumeRole and does not export the IAM user into this shell. +if [ -f "$role_source_file" ]; then + mkdir -p "$aws_dir" + if [ ! -f "$role_source_orig_file" ]; then + cp "$role_source_file" "$role_source_orig_file" + chmod 600 "$role_source_orig_file" + fi + + role_arn=$(jq -r '.RoleArn // empty' "$role_source_orig_file") + base_access_key_id=$(jq -r '.AccessKeyId // empty' "$role_source_orig_file") + base_secret_access_key=$(jq -r '.SecretAccessKey // empty' "$role_source_orig_file") + base_session_token=$(jq -r '.SessionToken // empty' "$role_source_orig_file") + if [ -z "$role_arn" ] || [ -z "$base_access_key_id" ] || [ -z "$base_secret_access_key" ]; then + echo "Role source file is incomplete." >&2 + return 1 2>/dev/null || exit 1 + fi + + run_as_user() { + unset AWS_PROFILE AWS_DEFAULT_PROFILE AWS_CONFIG_FILE AWS_SHARED_CREDENTIALS_FILE + export AWS_ACCESS_KEY_ID="$base_access_key_id" + export AWS_SECRET_ACCESS_KEY="$base_secret_access_key" + if [ -n "$base_session_token" ]; then + export AWS_SESSION_TOKEN="$base_session_token" + else + unset AWS_SESSION_TOKEN + fi + aws "$@" + } + + mfa_device_code=$(run_as_user iam list-mfa-devices | jq -r '.MFADevices[0].SerialNumber // empty') + if [ -z "$mfa_device_code" ]; then + unset -f run_as_user + echo "Failed to retrieve an MFA device. Check that the long-lived IAM user keys are valid." >&2 + return 1 2>/dev/null || exit 1 + fi + + echo "aws sts get-session-token --duration-seconds ${session_duration} --serial-number ${mfa_device_code} --token-code ${mfa_code}" + if ! ( + run_as_user sts get-session-token \ + --duration-seconds "$session_duration" \ + --serial-number "$mfa_device_code" \ + --token-code "$mfa_code" > "$tmp_creds_file" + ); then + unset -f run_as_user + echo "Request failed" >&2 + return 1 2>/dev/null || exit 1 + fi + unset -f run_as_user + + access_key_id=$(jq -r '.Credentials.AccessKeyId // empty' "$tmp_creds_file") + secret_access_key=$(jq -r '.Credentials.SecretAccessKey // empty' "$tmp_creds_file") + session_token=$(jq -r '.Credentials.SessionToken // empty' "$tmp_creds_file") + expiry=$(jq -r '.Credentials.Expiration // empty' "$tmp_creds_file") + rm -f "$tmp_creds_file" + if [ -z "$access_key_id" ] || [ -z "$secret_access_key" ] || [ -z "$session_token" ]; then + echo "Request failed" >&2 + return 1 2>/dev/null || exit 1 + fi + + jq -n \ + --arg RoleArn "$role_arn" \ + --arg AccessKeyId "$access_key_id" \ + --arg SecretAccessKey "$secret_access_key" \ + --arg SessionToken "$session_token" \ + '{RoleArn:$RoleArn, AccessKeyId:$AccessKeyId, SecretAccessKey:$SecretAccessKey, SessionToken:$SessionToken}' \ + > "$role_source_file" + chmod 600 "$role_source_file" + rm -f "$aws_creds_file" + unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN \ + AWS_PROFILE AWS_DEFAULT_PROFILE AWS_SHARED_CREDENTIALS_FILE AWS_CONFIG_FILE + + caller_arn=$(aws sts get-caller-identity --query Arn --output text) || { + echo "Failed to assume role ${role_arn} after MFA." >&2 + return 1 2>/dev/null || exit 1 + } + role_name=${role_arn##*/} + case "$caller_arn" in + arn:aws:sts::*:assumed-role/${role_name}/*) ;; + *) + echo "Refusing to use ${caller_arn}. Commands must run as assumed role ${role_arn}." >&2 + return 1 2>/dev/null || exit 1 + ;; + esac + + if expiry_local=$(date -d "$expiry" 2>/dev/null); then + echo "MFA session refreshed. Role ${role_arn} remains the identity used for commands. MFA expiry at: ${expiry_local}" + else + echo "MFA session refreshed. Role ${role_arn} remains the identity used for commands. MFA expiry at: ${expiry}" + fi + echo "Caller: ${caller_arn}" + return 0 2>/dev/null || exit 0 +fi + +mkdir -p "$aws_dir" + +if [ ! -f "$aws_creds_file" ]; then + echo "AWS credentials not found at ${aws_creds_file}." >&2 + echo "Long-lived keys have to be configured before requesting an MFA session." >&2 + return 1 2>/dev/null || exit 1 +fi + +if [ ! -f "$orig_creds_file" ]; then + echo "Backing up current credentials to ${orig_creds_file}" + cp "$aws_creds_file" "$orig_creds_file" + chmod 600 "$orig_creds_file" +fi + +# Always call STS with the long-lived keys, not a previous session token. +cp "$orig_creds_file" "$aws_creds_file" +chmod 600 "$aws_creds_file" + +mfa_device_code=$(aws iam list-mfa-devices | jq -r '.MFADevices[0].SerialNumber // empty') +if [ -z "$mfa_device_code" ]; then + echo "Failed to retrieve an MFA device. Check that the AWS CLI is using the long-lived credentials." >&2 + return 1 2>/dev/null || exit 1 +fi + +echo "aws sts get-session-token --duration-seconds ${session_duration} --serial-number ${mfa_device_code} --token-code ${mfa_code}" +if ! aws sts get-session-token \ + --duration-seconds "$session_duration" \ + --serial-number "$mfa_device_code" \ + --token-code "$mfa_code" > "$tmp_creds_file"; then + echo "Request failed" >&2 + return 1 2>/dev/null || exit 1 +fi + +access_key_id=$(jq -r '.Credentials.AccessKeyId // empty' "$tmp_creds_file") +secret_access_key=$(jq -r '.Credentials.SecretAccessKey // empty' "$tmp_creds_file") +session_token=$(jq -r '.Credentials.SessionToken // empty' "$tmp_creds_file") +expiry=$(jq -r '.Credentials.Expiration // empty' "$tmp_creds_file") + +if [ -z "$access_key_id" ] || [ -z "$secret_access_key" ] || [ -z "$session_token" ]; then + echo "Request failed" >&2 + return 1 2>/dev/null || exit 1 +fi + +cat > "$aws_creds_file" << EOF +[default] +aws_access_key_id = ${access_key_id} +aws_secret_access_key = ${secret_access_key} +aws_session_token = ${session_token} +EOF +chmod 600 "$aws_creds_file" +rm -f "$tmp_creds_file" + +# Environment variables override the credentials file, including keys that +# Portunus already exported, so these have to be set in this shell. +export AWS_ACCESS_KEY_ID="$access_key_id" +export AWS_SECRET_ACCESS_KEY="$secret_access_key" +export AWS_SESSION_TOKEN="$session_token" + +if expiry_local=$(date -d "$expiry" 2>/dev/null); then + echo "All set. Expiry at: ${expiry_local}" +else + echo "All set. Expiry at: ${expiry}" +fi +echo "Session credentials are exported and written to ${aws_creds_file}." diff --git a/script.sh b/script.sh index a4006cd..8662add 100644 --- a/script.sh +++ b/script.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -# Exit on any error -set -e +# Exit on any error, including a failed command in a pipeline +set -eo pipefail # Function to print an error and exit function error_exit { @@ -13,9 +13,11 @@ function error_exit { if [ -n "${PORTUNUS_TOKEN}" ]; then # Fetch and export environment variables from a given API - while IFS="=" read -r key value; do + portunus_env=$(print-env --api "https://portunusapiprod.ashishjullia.com/env" --format json | jq -r 'to_entries[] | "\(.key)=\(.value)"') || error_exit "Failed to fetch environment from Portunus" + while IFS="=" read -r key value; do + [ -n "$key" ] || continue export "$key=$(printf %b "$value")" - done < <(print-env --api "https://portunusapiprod.ashishjullia.com/env" --format json | jq -r 'to_entries[] | "\(.key)=\(.value)"') + done <<< "$portunus_env" # Conditionally install Terraform version if TF_VERSION is set if [ -n "${TF_VERSION}" ]; then @@ -26,12 +28,63 @@ if [ -n "${PORTUNUS_TOKEN}" ]; then echo "TF_VERSION is not set. Skipping Terraform installation." fi - # Conditionally configure AWS if AWS_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY are set + # Conditionally configure AWS if AWS_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY are set. + # When AWS_ROLE_TO_ASSUME is also set, the IAM user keys are stored outside the + # AWS credentials file. The default profile can only obtain credentials by + # assuming that role, and a failed assume fails the command. if [ -n "${AWS_REGION}" ] && [ -n "${AWS_ACCESS_KEY_ID}" ] && [ -n "${AWS_SECRET_ACCESS_KEY}" ]; then echo "Configuring AWS with region: ${AWS_REGION}" - aws configure set region "$AWS_REGION" || error_exit "Failed to set AWS region: ${AWS_REGION}" - aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" || error_exit "Failed to set AWS access key." - aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" || error_exit "Failed to set AWS secret access key." + if [ -n "${AWS_ROLE_TO_ASSUME}" ]; then + mkdir -p "${HOME}/.aws" + chmod 700 "${HOME}/.aws" + jq -n \ + --arg RoleArn "$AWS_ROLE_TO_ASSUME" \ + --arg AccessKeyId "$AWS_ACCESS_KEY_ID" \ + --arg SecretAccessKey "$AWS_SECRET_ACCESS_KEY" \ + --arg SessionToken "${AWS_SESSION_TOKEN:-}" \ + '{RoleArn:$RoleArn, AccessKeyId:$AccessKeyId, SecretAccessKey:$SecretAccessKey, SessionToken:$SessionToken}' \ + > "${HOME}/.aws/role-source.json" || error_exit "Failed to store role source credentials." + chmod 600 "${HOME}/.aws/role-source.json" + # A default access key in this file wins over the role and would run commands as the IAM user. + rm -f "${HOME}/.aws/credentials" + cat > "${HOME}/.aws/config" << EOF +[default] +region = ${AWS_REGION} +credential_process = /usr/local/bin/aws-role-credentials +EOF + chmod 600 "${HOME}/.aws/config" + unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN \ + AWS_PROFILE AWS_DEFAULT_PROFILE AWS_SHARED_CREDENTIALS_FILE AWS_CONFIG_FILE \ + AWS_CONTAINER_CREDENTIALS_RELATIVE_URI AWS_CONTAINER_CREDENTIALS_FULL_URI \ + AWS_CONTAINER_AUTHORIZATION_TOKEN AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE \ + AWS_WEB_IDENTITY_TOKEN_FILE AWS_ROLE_ARN AWS_ROLE_SESSION_NAME AWS_CREDENTIAL_EXPIRATION + caller_arn=$(aws sts get-caller-identity --query Arn --output text) || error_exit "Failed to assume role: ${AWS_ROLE_TO_ASSUME}" + role_name=${AWS_ROLE_TO_ASSUME##*/} + case "$caller_arn" in + arn:aws:sts::*:assumed-role/${role_name}/*) ;; + *) error_exit "Refusing to open a shell. AWS CLI resolved to ${caller_arn}, not assumed role ${AWS_ROLE_TO_ASSUME}." ;; + esac + expiry="" + if [ -f "${HOME}/.aws/role-expiration" ]; then + expiry=$(cat "${HOME}/.aws/role-expiration") + fi + if [ -n "$expiry" ] && expiry_local=$(date -d "$expiry" 2>/dev/null); then + expiry_display=$expiry_local + else + expiry_display=${expiry:-unknown} + fi + echo "Assumed role ${AWS_ROLE_TO_ASSUME}" + echo "Caller: ${caller_arn}" + echo "Session expires at: ${expiry_display}. The AWS CLI assumes this role again when it expires." + echo "Commands will not run with the IAM user keys. If the role cannot be assumed, the command fails." + echo "Run dev with no project to start a container that does not assume this role." + else + aws configure set region "$AWS_REGION" || error_exit "Failed to set AWS region: ${AWS_REGION}" + aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID" || error_exit "Failed to set AWS access key." + aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" || error_exit "Failed to set AWS secret access key." + fi + elif [ -n "${AWS_ROLE_TO_ASSUME:-}" ]; then + error_exit "AWS_ROLE_TO_ASSUME is set, but AWS_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY are required to assume it." else echo "AWS configuration variables are not fully set. Skipping AWS configuration." fi @@ -41,18 +94,12 @@ if [ -n "${PORTUNUS_TOKEN}" ]; then aws eks update-kubeconfig --region "$AWS_REGION" --name "$NAME_OF_CLUSTER" || error_exit "Failed to update kubeconfig for cluster: ${NAME_OF_CLUSTER}" fi - # Install specified Flux version if provided - if [[ -n "$FLUX_VERSION" ]]; then - echo "Installing Flux version: ${FLUX_VERSION}" - curl -s https://fluxcd.io/install.sh | bash || error_exit "Failed to install Flux version: ${FLUX_VERSION}" - fi - # Conditionally install Node.js version if NODE_VERSION is set if [ -n "${NODE_VERSION}" ]; then echo "NODE_VERSION is set to ${NODE_VERSION}. Installing Node.js version: ${NODE_VERSION}" export NVM_DIR="/usr/local/nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm - nvm install $NODE_VERSION + nvm install "$NODE_VERSION" else echo "NODE_VERSION is not set. Skipping Node.js installation." fi @@ -60,7 +107,7 @@ if [ -n "${PORTUNUS_TOKEN}" ]; then # Authenticate GitHub CLI if GITHUB_TOKEN is provided if [ -n "${GH_CLI_TOKEN}" ]; then echo "Authenticating GitHub CLI..." - gh auth login --with-token <<< $GH_CLI_TOKEN + gh auth login --with-token <<< "$GH_CLI_TOKEN" gh auth setup-git else echo "GH_CLI_TOKEN is not set. Skipping GitHub CLI authentication."