diff --git a/deployments/liqo/templates/liqo-wireguard-gateway-server-template-eks.yaml b/deployments/liqo/templates/liqo-wireguard-gateway-server-template-eks.yaml index 150b9a0aa5..e59203d8bb 100644 --- a/deployments/liqo/templates/liqo-wireguard-gateway-server-template-eks.yaml +++ b/deployments/liqo/templates/liqo-wireguard-gateway-server-template-eks.yaml @@ -1,9 +1,9 @@ -{{- $templateConfig := (merge (dict "name" "wireguard-server-eks" "module" "networking") .) -}} +{{- $templateConfig := (merge (dict "name" "wireguard-server" "module" "networking") .) -}} {{- $gatewayConfig := (merge (dict "name" "gateway" "module" "networking" "version" .Values.networking.gatewayTemplates.container.gateway.image.version) .) -}} {{- $wireguardConfig := (merge (dict "name" "gateway-wireguard" "module" "networking" "version" .Values.networking.gatewayTemplates.container.wireguard.image.version) .) -}} {{- $geneveConfig := (merge (dict "name" "gateway-geneve" "module" "networking" "version" .Values.networking.gatewayTemplates.container.geneve.image.version) .) -}} -{{- if .Values.networking.enabled }} +{{- if and .Values.networking.enabled .Values.authentication.awsConfig.accessKeyId }} apiVersion: networking.liqo.io/v1beta1 kind: WgGatewayServerTemplate diff --git a/deployments/liqo/templates/liqo-wireguard-gateway-server-template.yaml b/deployments/liqo/templates/liqo-wireguard-gateway-server-template.yaml index a4a9a3b871..880bdd815f 100644 --- a/deployments/liqo/templates/liqo-wireguard-gateway-server-template.yaml +++ b/deployments/liqo/templates/liqo-wireguard-gateway-server-template.yaml @@ -3,7 +3,7 @@ {{- $wireguardConfig := (merge (dict "name" "gateway-wireguard" "module" "networking" "version" .Values.networking.gatewayTemplates.container.wireguard.image.version) .) -}} {{- $geneveConfig := (merge (dict "name" "gateway-geneve" "module" "networking" "version" .Values.networking.gatewayTemplates.container.geneve.image.version) .) -}} -{{- if .Values.networking.enabled }} +{{- if and .Values.networking.enabled (not .Values.authentication.awsConfig.accessKeyId) }} apiVersion: networking.liqo.io/v1beta1 kind: WgGatewayServerTemplate diff --git a/pkg/identityManager/iamIdentityProvider.go b/pkg/identityManager/iamIdentityProvider.go index 2fa0958411..095b6daac7 100644 --- a/pkg/identityManager/iamIdentityProvider.go +++ b/pkg/identityManager/iamIdentityProvider.go @@ -162,7 +162,7 @@ func (identityProvider *iamIdentityProvider) ApproveSigningRequest(ctx context.C } // the IAM username has to have <= 64 characters - s := fmt.Sprintf("%s-%s", username, organization) + s := fmt.Sprintf("%s-%s-%s", username, organization, identityProvider.localClusterID) h := sha256.New() _, _ = h.Write([]byte(s)) bs := h.Sum(nil) @@ -317,6 +317,42 @@ func (identityProvider *iamIdentityProvider) ensureIamAccessKey(ctx context.Cont } createAccessKeyResult, err := iamSvc.CreateAccessKeyWithContext(ctx, createAccessKey) + if err == nil { + return createAccessKeyResult.AccessKey, nil + } + + // if the error is limit exceeded, we have to delete an existing access key + if aerr, ok := err.(awserr.Error); ok { //nolint:errorlint // aws does not export a specific error type + if aerr.Code() == iam.ErrCodeLimitExceededException { + klog.Warningf("IAM user %v has reached the limit of access keys, Liqo will delete an existing access key", username) + var accessKeyList *iam.ListAccessKeysOutput + accessKeyList, err = iamSvc.ListAccessKeysWithContext(ctx, &iam.ListAccessKeysInput{ + UserName: aws.String(username), + }) + if err != nil { + klog.Error(err) + return nil, err + } + + if len(accessKeyList.AccessKeyMetadata) == 0 { + klog.Error("no access key found") + return nil, fmt.Errorf("no access key found") + } + for _, accessKey := range accessKeyList.AccessKeyMetadata { + _, err = iamSvc.DeleteAccessKeyWithContext(ctx, &iam.DeleteAccessKeyInput{ + AccessKeyId: accessKey.AccessKeyId, + UserName: aws.String(username), + }) + if err != nil { + klog.Error(err) + return nil, err + } + } + + createAccessKeyResult, err = iamSvc.CreateAccessKeyWithContext(ctx, createAccessKey) + } + } + if err != nil { klog.Error(err) return nil, err diff --git a/pkg/liqoctl/install/eks/policy.go b/pkg/liqoctl/install/eks/policy.go index 9418a0eec8..2207b899f6 100644 --- a/pkg/liqoctl/install/eks/policy.go +++ b/pkg/liqoctl/install/eks/policy.go @@ -37,6 +37,8 @@ var policy = PolicyDocument{ Action: []string{ "iam:CreateUser", "iam:CreateAccessKey", + "iam:ListAccessKeys", + "iam:DeleteAccessKey", }, Resource: "*", }, diff --git a/test/e2e/pipeline/infra/eks/clean.sh b/test/e2e/pipeline/infra/eks/clean.sh new file mode 100755 index 0000000000..3e04fcb359 --- /dev/null +++ b/test/e2e/pipeline/infra/eks/clean.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# This scripts expects the following variables to be set: +# CLUSTER_NUMBER -> the number of liqo clusters +# K8S_VERSION -> the Kubernetes version +# CNI -> the CNI plugin used +# TMPDIR -> the directory where the test-related files are stored +# BINDIR -> the directory where the test-related binaries are stored +# TEMPLATE_DIR -> the directory where to read the cluster templates +# NAMESPACE -> the namespace where liqo is running +# KUBECONFIGDIR -> the directory where the kubeconfigs are stored +# LIQO_VERSION -> the liqo version to test +# INFRA -> the Kubernetes provider for the infrastructure +# LIQOCTL -> the path where liqoctl is stored +# KUBECTL -> the path where kubectl is stored +# EKSCTL -> the path where eksctl is stored +# AWS_CLI -> the path where aws-cli is stored +# POD_CIDR_OVERLAPPING -> the pod CIDR of the clusters is overlapping +# CLUSTER_TEMPLATE_FILE -> the file where the cluster template is stored + +set -e # Fail in case of error +set -o nounset # Fail if undefined variables are used +set -o pipefail # Fail if one of the piped commands fails + +error() { + local sourcefile=$1 + local lineno=$2 + echo "An error occurred at $sourcefile:$lineno." +} +trap 'error "${BASH_SOURCE}" "${LINENO}"' ERR + +CLUSTER_NAME=cluster +RUNNER_NAME=${RUNNER_NAME:-"test"} +CLUSTER_NAME="${RUNNER_NAME}-${CLUSTER_NAME}" + +PIDS=() + +# Cleaning all remaining clusters +for i in $(seq 1 "${CLUSTER_NUMBER}") +do + # if the cluster exists, delete it + if "${EKSCTL}" get cluster --name "${CLUSTER_NAME}${i}" --region "eu-central-1" &> /dev/null; then + echo "Deleting cluster ${CLUSTER_NAME}${i}" + else + echo "Cluster ${CLUSTER_NAME}${i} does not exist" + continue + fi + "${EKSCTL}" delete cluster --name "${CLUSTER_NAME}${i}" --region "eu-central-1" --wait --force & + PIDS+=($!) +done + +for PID in "${PIDS[@]}"; do + wait "${PID}" +done diff --git a/test/e2e/pipeline/infra/eks/pre-requirements.sh b/test/e2e/pipeline/infra/eks/pre-requirements.sh new file mode 100755 index 0000000000..99793cbae1 --- /dev/null +++ b/test/e2e/pipeline/infra/eks/pre-requirements.sh @@ -0,0 +1,84 @@ +#!/bin/bash +#shellcheck disable=SC1091 + +# This scripts expects the following variables to be set: +# CLUSTER_NUMBER -> the number of liqo clusters +# K8S_VERSION -> the Kubernetes version +# CNI -> the CNI plugin used +# TMPDIR -> the directory where the test-related files are stored +# BINDIR -> the directory where the test-related binaries are stored +# TEMPLATE_DIR -> the directory where to read the cluster templates +# NAMESPACE -> the namespace where liqo is running +# KUBECONFIGDIR -> the directory where the kubeconfigs are stored +# LIQO_VERSION -> the liqo version to test +# INFRA -> the Kubernetes provider for the infrastructure +# LIQOCTL -> the path where liqoctl is stored +# KUBECTL -> the path where kubectl is stored +# HELM -> the path where helm is stored +# EKSCTL -> the path where eksctl is stored +# AWS_CLI -> the path where aws-cli is stored +# POD_CIDR_OVERLAPPING -> the pod CIDR of the clusters is overlapping +# CLUSTER_TEMPLATE_FILE -> the file where the cluster template is stored + +set -e # Fail in case of error +set -o nounset # Fail if undefined variables are used +set -o pipefail # Fail if one of the piped commands fails + +error() { + local sourcefile=$1 + local lineno=$2 + echo "An error occurred at $sourcefile:$lineno." +} +trap 'error "${BASH_SOURCE}" "${LINENO}"' ERR + +FILEPATH=$(realpath "$0") +WORKDIR=$(dirname "$FILEPATH") + +# shellcheck source=../../utils.sh +source "$WORKDIR/../../utils.sh" + +setup_arch_and_os + +install_kubectl "${OS}" "${ARCH}" "${K8S_VERSION}" + +install_helm "${OS}" "${ARCH}" + +if ! command -v "${EKSCTL}" &> /dev/null +then + ARCH=amd64 + PLATFORM=$(uname -s)_$ARCH + echo "WARNING: eksctl could not be found. Downloading and installing it locally..." + if ! curl --fail -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"; then + echo "Error: Unable to download eksctl for '${OS}-${ARCH}'" + return 1 + fi + tar -xzf "eksctl_$PLATFORM.tar.gz" && rm "eksctl_$PLATFORM.tar.gz" + mv eksctl "${EKSCTL}" +fi +chmod +x "${EKSCTL}" +echo "eksctl version:" +"${EKSCTL}" version + +if ! command -v "${AWS_CLI}" &> /dev/null +then + case $ARCH in + arm64) AWS_ARCH="aarch64";; + arm) AWS_ARCH="aarch64";; + armv5) AWS_ARCH="aaarch64";; + armv6) AWS_ARCH="aarch64";; + amd64) AWS_ARCH="x86_64";; + 386) AWS_ARCH="x86_64";; + *) echo "Error architecture '${ARCH}' unknown"; exit 1 ;; + esac + echo "WARNING: aws-cli could not be found. Downloading and installing it locally..." + if ! curl --fail -sLO "https://awscli.amazonaws.com/awscli-exe-linux-$AWS_ARCH.zip"; then + echo "Error: Unable to download aws-cli for '${OS}-${ARCH}'" + return 1 + fi + unzip awscli-exe-linux-${AWS_ARCH}.zip + ./aws/install -i "${BINDIR}/aws-tmp" -b "${BINDIR}" + rm -rf aws awscli-exe-linux-${AWS_ARCH}.zip +fi +chmod +x "${AWS_CLI}" +echo "aws-cli version:" +"${AWS_CLI}" --version diff --git a/test/e2e/pipeline/infra/eks/setup.sh b/test/e2e/pipeline/infra/eks/setup.sh new file mode 100755 index 0000000000..50ea2f3f7b --- /dev/null +++ b/test/e2e/pipeline/infra/eks/setup.sh @@ -0,0 +1,95 @@ +#!/bin/bash +#shellcheck disable=SC1091 + +# This scripts expects the following variables to be set: +# CLUSTER_NUMBER -> the number of liqo clusters +# K8S_VERSION -> the Kubernetes version +# CNI -> the CNI plugin used +# TMPDIR -> the directory where the test-related files are stored +# BINDIR -> the directory where the test-related binaries are stored +# TEMPLATE_DIR -> the directory where to read the cluster templates +# NAMESPACE -> the namespace where liqo is running +# KUBECONFIGDIR -> the directory where the kubeconfigs are stored +# LIQO_VERSION -> the liqo version to test +# INFRA -> the Kubernetes provider for the infrastructure +# LIQOCTL -> the path where liqoctl is stored +# KUBECTL -> the path where kubectl is stored +# HELM -> the path where helm is stored +# EKSCTL -> the path where eksctl is stored +# AWS_CLI -> the path where aws-cli is stored +# POD_CIDR_OVERLAPPING -> the pod CIDR of the clusters is overlapping +# CLUSTER_TEMPLATE_FILE -> the file where the cluster template is stored +# CNI -> the CNI plugin used + +set -e # Fail in case of error +set -o nounset # Fail if undefined variables are used +set -o pipefail # Fail if one of the piped commands fails + +error() { + local sourcefile=$1 + local lineno=$2 + echo "An error occurred at $sourcefile:$lineno." +} +trap 'error "${BASH_SOURCE}" "${LINENO}"' ERR + +FILEPATH=$(realpath "$0") +WORKDIR=$(dirname "$FILEPATH") + +# shellcheck source=../../utils.sh +source "$WORKDIR/../../utils.sh" + +CLUSTER_NAME=cluster + +export POD_CIDR=10.200.0.0/16 +export POD_CIDR_OVERLAPPING=${POD_CIDR_OVERLAPPING:-"false"} + +RUNNER_NAME=${RUNNER_NAME:-"test"} +CLUSTER_NAME="${RUNNER_NAME}-${CLUSTER_NAME}" + +PIDS=() + +for i in $(seq 1 "${CLUSTER_NUMBER}"); +do + if [[ ${POD_CIDR_OVERLAPPING} != "true" ]]; then + export POD_CIDR="10.$((i * 10)).0.0/16" + fi + echo "Creating cluster ${CLUSTER_NAME}${i}" + "${EKSCTL}" create cluster \ + --name "${CLUSTER_NAME}${i}" \ + --region "eu-central-1" \ + --instance-types c4.large,c5.large \ + --nodes 2 \ + --managed \ + --alb-ingress-access \ + --node-ami-family "AmazonLinux2" \ + --vpc-cidr "$POD_CIDR" \ + --kubeconfig "${TMPDIR}/kubeconfigs/liqo_kubeconf_${i}" & + PIDS+=($!) +done + +for PID in "${PIDS[@]}"; do + wait "${PID}" +done + +for i in $(seq 1 "${CLUSTER_NUMBER}"); +do + CURRENT_CONTEXT=$("${KUBECTL}" config current-context --kubeconfig "${TMPDIR}/kubeconfigs/liqo_kubeconf_${i}") + "${KUBECTL}" config set contexts."${CURRENT_CONTEXT}".namespace default --kubeconfig "${TMPDIR}/kubeconfigs/liqo_kubeconf_${i}" + + # install local-path storage class + install_local_path_storage "${TMPDIR}/kubeconfigs/liqo_kubeconf_${i}" + + # Install metrics-server + install_metrics_server "${TMPDIR}/kubeconfigs/liqo_kubeconf_${i}" + + # Install kyverno for network tests + install_kyverno "${TMPDIR}/kubeconfigs/liqo_kubeconf_${i}" + + # Install AWS Load Balancer Controller + "${HELM}" repo add eks https://aws.github.io/eks-charts + "${HELM}" repo update + "${HELM}" install aws-load-balancer-controller eks/aws-load-balancer-controller \ + -n kube-system \ + --set clusterName="${CLUSTER_NAME}${i}" \ + --kubeconfig "${TMPDIR}/kubeconfigs/liqo_kubeconf_${i}" +done diff --git a/test/e2e/pipeline/installer/liqoctl/setup.sh b/test/e2e/pipeline/installer/liqoctl/setup.sh index 4b290c0d50..1a19b58352 100755 --- a/test/e2e/pipeline/installer/liqoctl/setup.sh +++ b/test/e2e/pipeline/installer/liqoctl/setup.sh @@ -75,6 +75,21 @@ do if [[ "${INFRA}" == "k3s" ]]; then COMMON_ARGS=("${COMMON_ARGS[@]}" --pod-cidr "${POD_CIDR}" --service-cidr "${SERVICE_CIDR}") fi + if [[ "${INFRA}" == "eks" ]]; then + CLUSTER_NAME=cluster + RUNNER_NAME=${RUNNER_NAME:-"test"} + CLUSTER_NAME="${RUNNER_NAME}-${CLUSTER_NAME}" + COMMON_ARGS=("${COMMON_ARGS[@]}" --eks-cluster-region="eu-central-1" --eks-cluster-name="${CLUSTER_NAME}${i}") + # do not fail if variables are not set + set +u + if [[ "${LIQO_AWS_USERNAME}" != "" ]]; then + COMMON_ARGS=("${COMMON_ARGS[@]}" --user-name "${LIQO_AWS_USERNAME}") + fi + if [[ "${LIQO_AWS_POLICY_NAME}" != "" ]]; then + COMMON_ARGS=("${COMMON_ARGS[@]}" --policy-name "${LIQO_AWS_POLICY_NAME}") + fi + set -u + fi if [[ "${INFRA}" == "cluster-api" ]]; then LIQO_PROVIDER="kubeadm" COMMON_ARGS=("${COMMON_ARGS[@]}")