diff --git a/Dockerfile b/Dockerfile index 28c9350..afc2eea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.19.1 +FROM alpine:3.22.0 ARG USER=ext-installer ENV HOME /home/$USER @@ -9,6 +9,7 @@ RUN adduser -D $USER USER $USER WORKDIR $HOME -ADD install.sh . +COPY --chown=$USER:$USER install.sh . +RUN chmod +x install.sh ENTRYPOINT ["./install.sh"] diff --git a/README.md b/README.md index 61efee4..3fa8b7c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ list of all environment variables that can be configured: | EXTENSION_CHECKSUM_URL | No | "" | Can be set to the file containing the checksum to validate the downloaded
extension. Will skip the checksum validation if not provided.
Argo CD API server needs to have network access to this URL. | | MAX_DOWNLOAD_SEC | No | 30 | Total time in seconds allowed to download the extension. | | EXTENSION_JS_VARS | No | "" | Export the variables to `extension-$EXTENSION_JS_VARS` in js file within the extension folder. These variables will be exported as env variables with key `${EXTENSION_NAME}_VARS`.
The format should be `{key1=value1, key2=value2}`. | +| EXTENSION_GIT_TOKEN | No | "" | Token used for authentication when downloading the extension from a private Git repository. The token will be used in an `Authorization` header. | # Examples @@ -41,7 +42,7 @@ spec: spec: initContainers: - name: extension- - image: quay.io/argoprojlabs/argocd-extension-installer:v0.0.5@sha256:27e72f047298188e2de1a73a1901013c274c4760c92f82e6e46cd5fbd0957c6b + image: quay.io/argoprojlabs/argocd-extension-installer:v0.0.9 env: - name: EXTENSION_URL value: https://github.com/some-org/somerepo/releases/download/v0.0.1/extension.tar @@ -63,6 +64,51 @@ spec: > The tag digest can be obtained in quay by clicking in the "fetch tag" icon and select "Docker Pull (by digest)": > https://quay.io/repository/argoprojlabs/argocd-extension-installer?tab=tags +### Using private repositories + +If your extension is hosted in a private Git repository, you can provide a Git access token using the `EXTENSION_GIT_TOKEN` environment variable. This token will be used to set an `Authorization` header when downloading the extension archive and optional checksum file. + +The token can be injected either through a ConfigMap or a Secret. It is recommended to use a Kubernetes Secret to avoid exposing sensitive values in plain text. + +Supported services include GitHub, GitLab, Bitbucket, and generic Git servers. + +#### Example: Using a Kubernetes Secret + +Create a Kubernetes Secret that holds your Git access token: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: github-token-secret + namespace: argocd +type: Opaque +stringData: + EXTENSION_GIT_TOKEN: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +``` + + +Reference the token in your Argo CD server deployment: +```yaml + initContainers: + - name: extension- + image: quay.io/argoprojlabs/argocd-extension-installer:v0.0.9 + env: + - name: EXTENSION_URL + value: https://github.com/some-org/somerepo/releases/download/v0.0.1/extension.tar + - name: EXTENSION_GIT_TOKEN + valueFrom: + secretKeyRef: + name: github-token-secret + key: EXTENSION_GIT_TOKEN + volumeMounts: + - name: extensions + mountPath: /tmp/extensions/ + securityContext: + runAsUser: 1000 + allowPrivilegeEscalation: false +``` + ## Using ConfigMap The example below demonstrates how to define all extension @@ -99,7 +145,7 @@ spec: spec: initContainers: - name: extension - image: quay.io/argoprojlabs/argocd-extension-installer:v0.0.5@sha256:27e72f047298188e2de1a73a1901013c274c4760c92f82e6e46cd5fbd0957c6b + image: quay.io/argoprojlabs/argocd-extension-installer:v0.0.9 env: - name: EXTENSION_NAME valueFrom: diff --git a/install.sh b/install.sh index f1e7ffa..51b4742 100755 --- a/install.sh +++ b/install.sh @@ -28,18 +28,94 @@ finalizer() { } trap finalizer EXIT +# detect if URL is a Git repository URL +is_git_url() { + local url="$1" + case "$url" in + https://github.com/*|https://gitlab.com/*|https://bitbucket.org/*|*.git|*git*) + return 0 + ;; + *) + return 1 + ;; + esac +} + +# construct authorization header for Git API +get_git_auth_header() { + local url="$1" + local token="$2" + + if [ -z "$token" ]; then + echo "" + return + fi + + case "$url" in + https://github.com/*) + echo "Authorization: token $token" + ;; + https://gitlab.com/*) + echo "Authorization: Bearer $token" + ;; + https://bitbucket.org/*) + echo "Authorization: Bearer $token" + ;; + *) + # Generic Git token format + echo "Authorization: Bearer $token" + ;; + esac +} + # will download the extension respecting the max download # duration setting download_extension() { mkdir -p $download_dir echo "Downloading the UI extension..." - curl -Lf --max-time $download_max_sec $ext_url -o $ext_file + + # Check if this is a Git repository URL and token is provided + if is_git_url "$ext_url" && [ -n "$git_token" ]; then + echo "Detected Git repository URL with authentication token" + auth_header=$(get_git_auth_header "$ext_url" "$git_token") + + if [ -n "$auth_header" ]; then + echo "Using authenticated download for private repository" + curl -Lf --max-time $download_max_sec -H "$auth_header" "$ext_url" -o "$ext_file" + else + curl -Lf --max-time $download_max_sec "$ext_url" -o "$ext_file" + fi + elif is_git_url "$ext_url" && [ -z "$git_token" ]; then + echo "WARNING: Git repository URL detected but no EXTENSION_GIT_TOKEN provided" + echo "This may fail if the repository is private" + curl -Lf --max-time $download_max_sec "$ext_url" -o "$ext_file" + else + # Non-Git URL, use standard download + curl -Lf --max-time $download_max_sec "$ext_url" -o "$ext_file" + fi + + # Validate checksum if provided if [ "$checksum_url" != "" ]; then echo "Validating the UI extension checksum..." - expected_sha=$(curl -Lf $checksum_url | grep "$ext_filename" | awk '{print $1;}') + + # Apply same authentication logic for checksum URL if it's also a Git URL + if is_git_url "$checksum_url" && [ -n "$git_token" ]; then + auth_header=$(get_git_auth_header "$checksum_url" "$git_token") + + if [ -n "$auth_header" ]; then + expected_sha=$(curl -Lf -H "$auth_header" "$checksum_url" | grep "$ext_filename" | awk '{print $1;}') + else + expected_sha=$(curl -Lf "$checksum_url" | grep "$ext_filename" | awk '{print $1;}') + fi + else + expected_sha=$(curl -Lf "$checksum_url" | grep "$ext_filename" | awk '{print $1;}') + fi + current_sha=$(sha256sum $ext_file | awk '{print $1;}') if [ "$expected_sha" != "$current_sha" ]; then echo "ERROR: extension checksum mismatch" + echo "Expected: $expected_sha" + echo "Current: $current_sha" exit 1 fi fi @@ -69,7 +145,6 @@ install_extension() { fi echo "UI extension installed successfully" - } create_extension_js_file_with_vars() { @@ -103,6 +178,10 @@ if [ "$ext_url" = "" ]; then echo "error: the env var EXTENSION_URL must be provided" exit 1 fi + +# Git token for private repository access +git_token="${EXTENSION_GIT_TOKEN:-}" + checksum_url="${EXTENSION_CHECKSUM_URL:-}" download_max_sec="${MAX_DOWNLOAD_SEC:-30}" @@ -118,7 +197,12 @@ if [ -n "${ext_vars}" ]; then ext_vars=$(echo "$ext_vars" | jq -c '.') fi +# Log authentication status (without exposing token) +if [ -n "$git_token" ]; then + echo "Git authentication token detected for private repository access" +else + echo "No Git authentication token provided - public repositories only" +fi download_extension install_extension -