From e0684b6e6bfd3b4cf161b7e24fd5873abeff0736 Mon Sep 17 00:00:00 2001 From: Yury Kovalev <8366110+kovayur@users.noreply.github.com> Date: Thu, 24 Nov 2022 11:50:07 +0100 Subject: [PATCH] ROX-13396: Add SAML authentication method for AWS (#544) Co-authored-by: Marcin Owsiany --- .github/workflows/deploy-stage.yaml | 2 +- Makefile | 8 ++++ dev/env/defaults/00-defaults.env | 2 +- dev/env/defaults/cluster-type-colima/env | 2 +- dev/env/defaults/cluster-type-crc/env | 2 +- dev/env/defaults/cluster-type-minikube/env | 2 +- .../defaults/cluster-type-rancher-desktop/env | 2 +- dev/env/scripts/lib.sh | 2 +- dev/env/scripts/up.sh | 2 +- docs/development/secret-management.md | 21 ++++++-- .../helm/rhacs-terraform/terraform_cluster.sh | 5 +- dp-terraform/osd-cluster-idp-setup.sh | 5 +- scripts/lib/external_config.sh | 48 ++++++++++++++----- tools/requirements.txt | 1 + 14 files changed, 79 insertions(+), 25 deletions(-) create mode 100644 tools/requirements.txt diff --git a/.github/workflows/deploy-stage.yaml b/.github/workflows/deploy-stage.yaml index 3f10ae5c6..f47ea2557 100644 --- a/.github/workflows/deploy-stage.yaml +++ b/.github/workflows/deploy-stage.yaml @@ -38,7 +38,7 @@ jobs: - name: Run terraforming on THE stage cluster working-directory: ./dp-terraform/helm/rhacs-terraform env: - USE_AWS_VAULT: false + AWS_AUTH_HELPER: none # credentials are populated by the above action run: | set -euo pipefail ./terraform_cluster.sh stage acs-stage-dp-01 diff --git a/Makefile b/Makefile index 6da27c67d..b6e8f2d86 100644 --- a/Makefile +++ b/Makefile @@ -116,6 +116,14 @@ GINKGO_BIN := $(LOCAL_BIN_PATH)/ginkgo $(GINKGO_BIN): $(TOOLS_DIR)/go.mod $(TOOLS_DIR)/go.sum @cd $(TOOLS_DIR) && GOBIN=${LOCAL_BIN_PATH} $(GO) install github.com/onsi/ginkgo/v2/ginkgo +TOOLS_VENV_DIR := $(LOCAL_BIN_PATH)/tools_venv +$(TOOLS_VENV_DIR): + @set -e; \ + python3 -m venv $(TOOLS_VENV_DIR); \ + . $(TOOLS_VENV_DIR)/bin/activate; \ + pip install --upgrade pip==22.3.1; \ + pip install -r $(TOOLS_DIR)/requirements.txt + OPENAPI_GENERATOR ?= ${LOCAL_BIN_PATH}/openapi-generator NPM ?= "$(shell which npm)" openapi-generator: diff --git a/dev/env/defaults/00-defaults.env b/dev/env/defaults/00-defaults.env index d73614a41..011b64363 100644 --- a/dev/env/defaults/00-defaults.env +++ b/dev/env/defaults/00-defaults.env @@ -63,4 +63,4 @@ export DB_RESOURCES_DEFAULT='{"requests":{"cpu":"100m","memory":"300Mi"},"limits export RHACS_OPERATOR_RESOURCES_DEFAULTS='{"requests":{"cpu":"200m","memory":"300Mi"},"limits":{"cpu":"200m","memory":"300Mi"}}' export ENABLE_EXTERNAL_CONFIG_DEFAULT=false -export USE_AWS_VAULT_DEFAULT=false +export AWS_AUTH_HELPER_DEFAULT="" diff --git a/dev/env/defaults/cluster-type-colima/env b/dev/env/defaults/cluster-type-colima/env index 3280b93ce..e6df7cb74 100644 --- a/dev/env/defaults/cluster-type-colima/env +++ b/dev/env/defaults/cluster-type-colima/env @@ -11,4 +11,4 @@ else fi export ENABLE_EXTERNAL_CONFIG_DEFAULT="true" -export USE_AWS_VAULT_DEFAULT="true" +export AWS_AUTH_HELPER_DEFAULT="aws-vault" diff --git a/dev/env/defaults/cluster-type-crc/env b/dev/env/defaults/cluster-type-crc/env index 5d7b97ce1..cc9db1162 100644 --- a/dev/env/defaults/cluster-type-crc/env +++ b/dev/env/defaults/cluster-type-crc/env @@ -1,3 +1,3 @@ export ENABLE_CENTRAL_EXTERNAL_CERTIFICATE="true" export ENABLE_EXTERNAL_CONFIG_DEFAULT="true" -export USE_AWS_VAULT_DEFAULT="true" +export AWS_AUTH_HELPER_DEFAULT="aws-vault" diff --git a/dev/env/defaults/cluster-type-minikube/env b/dev/env/defaults/cluster-type-minikube/env index c4752f74d..11b9ce1fb 100644 --- a/dev/env/defaults/cluster-type-minikube/env +++ b/dev/env/defaults/cluster-type-minikube/env @@ -5,4 +5,4 @@ export OPERATOR_SOURCE_DEFAULT="quay" export INHERIT_IMAGEPULLSECRETS_DEFAULT="true" # pragma: allowlist secret export INSTALL_OLM_DEFAULT="true" export ENABLE_EXTERNAL_CONFIG_DEFAULT="true" -export USE_AWS_VAULT_DEFAULT="true" +export AWS_AUTH_HELPER_DEFAULT="aws-vault" diff --git a/dev/env/defaults/cluster-type-rancher-desktop/env b/dev/env/defaults/cluster-type-rancher-desktop/env index fd4bb34de..2902f9fc1 100644 --- a/dev/env/defaults/cluster-type-rancher-desktop/env +++ b/dev/env/defaults/cluster-type-rancher-desktop/env @@ -8,4 +8,4 @@ export RANCHER_DESKTOP_BIN=${RANCHER_DESKTOP_BIN:-"${HOME}/.rd/bin"} export KUBECTL_DEFAULT="${RANCHER_DESKTOP_BIN}/kubectl" export DOCKER_DEFAULT="${RANCHER_DESKTOP_BIN}/docker" export ENABLE_EXTERNAL_CONFIG_DEFAULT="true" -export USE_AWS_VAULT_DEFAULT="true" +export AWS_AUTH_HELPER_DEFAULT="aws-vault" diff --git a/dev/env/scripts/lib.sh b/dev/env/scripts/lib.sh index dac55da46..3c6f4be18 100644 --- a/dev/env/scripts/lib.sh +++ b/dev/env/scripts/lib.sh @@ -78,7 +78,7 @@ init() { done export ENABLE_EXTERNAL_CONFIG="${ENABLE_EXTERNAL_CONFIG:-$ENABLE_EXTERNAL_CONFIG_DEFAULT}" - export USE_AWS_VAULT="${USE_AWS_VAULT:-$USE_AWS_VAULT_DEFAULT}" + export AWS_AUTH_HELPER="${AWS_AUTH_HELPER:-$AWS_AUTH_HELPER_DEFAULT}" export KUBECTL=${KUBECTL:-$KUBECTL_DEFAULT} export ACSMS_NAMESPACE="${ACSMS_NAMESPACE:-$ACSMS_NAMESPACE_DEFAULT}" diff --git a/dev/env/scripts/up.sh b/dev/env/scripts/up.sh index ff5744814..8f4ccc475 100755 --- a/dev/env/scripts/up.sh +++ b/dev/env/scripts/up.sh @@ -30,7 +30,7 @@ Namespace: ${ACSMS_NAMESPACE} Inheriting ImagePullSecrets for Quay.io: ${INHERIT_IMAGEPULLSECRETS} Installing RHACS Operator: ${INSTALL_OPERATOR} Enable External Config: ${ENABLE_EXTERNAL_CONFIG} -Use AWS Vault: ${USE_AWS_VAULT} +AWS Auth Helper: ${AWS_AUTH_HELPER:-none} Debugging Mode: ${DEBUG_PODS} EOF diff --git a/docs/development/secret-management.md b/docs/development/secret-management.md index fa522ebe5..48d88f64a 100644 --- a/docs/development/secret-management.md +++ b/docs/development/secret-management.md @@ -5,6 +5,7 @@ Application Secrets are stored in AWS Parameter Store. The following tools are used to integrate with Parameter Store: - [chamber](https://github.com/segmentio/chamber) - CLI for managing secrets - [aws-vault](https://github.com/99designs/aws-vault) - supplementary tool to store AWS credentials in the secure local storage +- [aws-saml.py](https://gitlab.corp.redhat.com/compute/aws-automation) - helper tool for authenticating in AWS using SAML The main usage is to load the secrets as environment variables for deploying a service. Secrets are divided to subgroups per each service. The following services are currently exist: @@ -20,10 +21,22 @@ Secrets are divided to subgroups per each service. The following services are cu - acs-prod-dp-01 ## Instructions -No additional steps are required to use the tools. -Dependent scripts source the [helper script](./../../scripts/lib/external_config.sh) with command wrapper. -With this script, the tools are automatically installed from the appropriate `Makefile` targets. -It is also recommended to install the tools in the local go bin folder so that you can easily use `chamber` from the command line. +- `AWS_AUTH_HELPER` environment variable selects the appropriate authentication method within the deployment scripts. Possible options are: + - `aws-vault` + - `aws-saml` + - `none` (default) +- Depending on the environment, the following choices are set: + + | Source | Target | AWS_AUTH_HELPER | + |--------|-------------|-----------------| + | local | dev | aws-vault | + | local | stage,prod | aws-saml | + | CI/CD | stage,prod | none | + +- For SAML authentication, you must have access to the [`aws-automation` git repository](https://gitlab.corp.redhat.com/compute/aws-automation) for the script to be able to download the tool (VPN is required). +- Dependent scripts source the [helper script](./../../scripts/lib/external_config.sh) with `chamber` command wrapper; +- With this script, the tools are automatically installed from the appropriate `Makefile` targets; +- It is also recommended to install the tools in the local bin folder so that you can easily use `chamber`, `aws-saml.py` and `aws-vault` from the command line; ## Tips / Examples ### Useful environment aliases diff --git a/dp-terraform/helm/rhacs-terraform/terraform_cluster.sh b/dp-terraform/helm/rhacs-terraform/terraform_cluster.sh index 3941aa82a..2d911c9c5 100755 --- a/dp-terraform/helm/rhacs-terraform/terraform_cluster.sh +++ b/dp-terraform/helm/rhacs-terraform/terraform_cluster.sh @@ -16,7 +16,10 @@ fi ENVIRONMENT=$1 CLUSTER_NAME=$2 -export AWS_PROFILE="$ENVIRONMENT" +export AWS_AUTH_HELPER="${AWS_AUTH_HELPER:-aws-saml}" +if [[ "$AWS_AUTH_HELPER" == "aws-vault" ]]; then + export AWS_PROFILE="$ENVIRONMENT" +fi init_chamber diff --git a/dp-terraform/osd-cluster-idp-setup.sh b/dp-terraform/osd-cluster-idp-setup.sh index f0c0c2671..d3a09066b 100755 --- a/dp-terraform/osd-cluster-idp-setup.sh +++ b/dp-terraform/osd-cluster-idp-setup.sh @@ -24,7 +24,10 @@ fi ENVIRONMENT=$1 CLUSTER_NAME=$2 -export AWS_PROFILE="$ENVIRONMENT" +export AWS_AUTH_HELPER="${AWS_AUTH_HELPER:-aws-saml}" +if [[ "$AWS_AUTH_HELPER" == "aws-vault" ]]; then + export AWS_PROFILE="$ENVIRONMENT" +fi case $ENVIRONMENT in stage) diff --git a/scripts/lib/external_config.sh b/scripts/lib/external_config.sh index ba8670376..b1843f71d 100644 --- a/scripts/lib/external_config.sh +++ b/scripts/lib/external_config.sh @@ -1,14 +1,12 @@ #!/usr/bin/env bash GITROOT="${GITROOT:-"$(git rev-parse --show-toplevel)"}" -USE_AWS_VAULT="${USE_AWS_VAULT:-true}" ENABLE_EXTERNAL_CONFIG="${ENABLE_EXTERNAL_CONFIG:-true}" -# shellcheck source=/dev/null +# shellcheck source=scripts/lib/log.sh source "$GITROOT/scripts/lib/log.sh" export AWS_REGION="${AWS_REGION:-"us-east-1"}" -export AWS_PROFILE=${AWS_PROFILE:-"dev"} ensure_tool_installed() { make -s -C "$GITROOT" "$GITROOT/bin/$1" @@ -24,13 +22,41 @@ init_chamber() { return fi - if [[ "$USE_AWS_VAULT" = true ]]; then - ensure_tool_installed aws-vault - ensure_aws_profile_exists - elif [[ -z "${AWS_SESSION_TOKEN:-}" ]] || [[ -z "${AWS_ACCESS_KEY_ID:-}" ]] || [[ -z "${AWS_SECRET_ACCESS_KEY:-}" ]]; then - die "Error: Unable to resolve one of the following environment variables: AWS_SESSION_TOKEN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY. - Please set them or use aws-vault by setting USE_AWS_VAULT=true." - fi + AWS_AUTH_HELPER="${AWS_AUTH_HELPER:-none}" + case $AWS_AUTH_HELPER in + aws-saml) + export AWS_PROFILE="saml" + ensure_tool_installed tools_venv + # shellcheck source=/dev/null # The script may not exist + source "$GITROOT/bin/tools_venv/bin/activate" + # ensure a valid kerberos ticket exist + if ! klist -s >/dev/null 2>&1; then + log "Getting a Kerberos ticket" + kinit + fi + aws-saml.py # TODO(ROX-12222): Skip if existing token has not yet expired + ;; + aws-vault) + export AWS_PROFILE="${AWS_PROFILE:-dev}" + ensure_tool_installed aws-vault + ensure_aws_profile_exists + ;; + none) + if [[ -z "${AWS_SESSION_TOKEN:-}" ]] || [[ -z "${AWS_ACCESS_KEY_ID:-}" ]] || [[ -z "${AWS_SECRET_ACCESS_KEY:-}" ]]; then + auth_init_error "Unable to resolve the authentication method" + fi + ;; + *) + auth_init_error "Unsupported AWS_AUTH_HELPER=$AWS_AUTH_HELPER" + ;; + esac +} + +auth_init_error() { + die "Error: $1. Choose one of the following options: + 1) SAML (export AWS_AUTH_HELPER=aws-saml) + 2) aws-vault (export AWS_AUTH_HELPER=aws-vault) + 3) Unset AWS_AUTH_HELPER and export AWS_SESSION_TOKEN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY environment variables" } ensure_aws_profile_exists() { @@ -74,7 +100,7 @@ run_chamber() { # External config disabled. Using 'null' backend for chamber args=("-b" "null" "${args[@]}") fi - if [[ "$USE_AWS_VAULT" = true ]]; then + if [[ "$AWS_AUTH_HELPER" == "aws-vault" ]]; then aws-vault exec "${AWS_PROFILE}" -- chamber "${args[@]}" else chamber "${args[@]}" diff --git a/tools/requirements.txt b/tools/requirements.txt new file mode 100644 index 000000000..1fe404f9f --- /dev/null +++ b/tools/requirements.txt @@ -0,0 +1 @@ +git+https://gitlab.corp.redhat.com/compute/aws-automation.git@dc044fef