diff --git a/bash/containers/falcon-container-sensor-pull/README.md b/bash/containers/falcon-container-sensor-pull/README.md index 73ef137..fcdb61d 100644 --- a/bash/containers/falcon-container-sensor-pull/README.md +++ b/bash/containers/falcon-container-sensor-pull/README.md @@ -102,6 +102,16 @@ Optional Flags: By default, the image name and tag are appended. Use --copy-omit-image-name and/or --copy-custom-tag to change that behavior. -v, --version Specify sensor version to retrieve from the registry + + Accepts version strings or channel keywords: + ------------------------------------------- + latest Latest sensor version (default) + N-1 One release prior to the latest + N-2 Two releases prior to the latest + LTS Latest LTS release + LTS-1 Previous LTS release + 7.33 Latest build of version 7.33.x + 7.33.0-18606 Specific sensor build -p, --platform Specify sensor platform to retrieve, e.g., x86_64, aarch64 -t, --type Specify which sensor to download (Default: falcon-container) @@ -148,7 +158,7 @@ Help Options: | `-s`, `--client-secret ` | `$FALCON_CLIENT_SECRET` | `None` (Required) | CrowdStrike API Client Secret | | `-r`, `--region ` | `$FALCON_CLOUD` | `us-1` (Optional) | CrowdStrike Region.
\**Auto-discovery is only available for [`us-1, us-2, us-3, eu-1`] regions.* | | `-c`, `--copy ` | `$COPY` | `None` (Optional) | Registry you want to copy the sensor image to. Example: `myregistry.com/mynamespace`.
*\*By default, the image name and tag are appended. Use `--copy-omit-image-name` and/or `--copy-custom-tag` to change that behavior.* | -| `-v`, `--version ` | `$SENSOR_VERSION` | `None` (Optional) | Specify sensor version to retrieve from the registry | +| `-v`, `--version ` | `$SENSOR_VERSION` | `None` (Optional) | Specify sensor version to retrieve from the registry. Accepts version strings (e.g., `7.33`, `7.33.0`) or channel keywords: `latest`, `N-1`, `N-2`, `LTS`, `LTS-1` | | `-p`, `--platform ` | `$SENSOR_PLATFORM` | `None` (Optional) | Specify sensor platform to retrieve from the registry | | `-t`, `--type ` | `$SENSOR_TYPE` | `falcon-container` (Optional) | Specify which sensor to download [`falcon-container`, `falcon-container-regional`, `falcon-sensor`, `falcon-sensor-regional`, `falcon-kac`, `falcon-kac-regional`, `falcon-snapshot`, `falcon-imageanalyzer`, `falcon-imageanalyzer-regional`, `fcs`, `falcon-jobcontroller`, `falcon-registryassessmentexecutor`] ([see more details below](#sensor-types)) | | `--runtime` | `$CONTAINER_TOOL` | `docker` (Optional) | Use a different container runtime [docker, podman, skopeo]. **Default is Docker**. | @@ -190,6 +200,48 @@ The following sensor types are available to download: | `falcon-jobcontroller` | The Self Hosted Registry Assessment Jobs Controller | | `falcon-registryassessmentexecutor` | The Self Hosted Registry Assessment Executor | +### Version Channels + +The `-v, --version` flag accepts channel keywords for policy-driven deployments without needing to know exact version numbers: + +| Keyword | Description | +| :------- | :---------------------------------- | +| `latest` | Latest sensor version (default) | +| `N-1` | One release prior to the latest | +| `N-2` | Two releases prior to the latest | +| `LTS` | Latest LTS release | +| `LTS-1` | Previous LTS release | + +Channel keywords are case-insensitive (`n-1`, `N-1`, `lts`, `LTS` all work). N-1/N-2 step back through releases and exclude LTS tags from consideration. No additional API scopes are required — channels are resolved entirely from existing registry tag data. + +> [!NOTE] +> LTS (Long Term Support) sensor release tags are not yet generally available. The `LTS` and `LTS-1` keywords are included ahead of that release and will return an error until LTS-tagged images are published to the registry. + +```shell +# Pull latest (default behavior) +./falcon-container-sensor-pull.sh \ +--client-id \ +--client-secret + +# Pull the previous major.minor release (N-1) +./falcon-container-sensor-pull.sh \ +--client-id \ +--client-secret \ +--version N-1 + +# Pull the latest LTS release +./falcon-container-sensor-pull.sh \ +--client-id \ +--client-secret \ +--version LTS + +# Pull the previous LTS release +./falcon-container-sensor-pull.sh \ +--client-id \ +--client-secret \ +--version LTS-1 +``` + ### Examples #### Example downloading the Falcon Kubernetes Admission Controller @@ -231,6 +283,37 @@ The following example will print the image repository path with the latest image Example output: `registry.crowdstrike.com/falcon-sensor/us-1/release/falcon-sensor:7.29.0-15501-1.falcon-linux.Release.US-1` +#### Example pinning to a version channel for automation + +Channel keywords are useful in CI/CD or GitOps pipelines where you want to track a release channel without hardcoding version numbers. The following example resolves the N-1 channel to a concrete image path that can be pinned into a Kubernetes manifest or Helm value. + +```shell +./falcon-container-sensor-pull.sh \ +--client-id \ +--client-secret \ +--type falcon-sensor \ +--version N-1 \ +--get-image-path +``` + +Example output: `registry.crowdstrike.com/falcon-sensor/release/falcon-sensor:7.30.0-15400-1` + +#### Example mirroring a version channel to another registry + +The following example resolves the latest LTS release and copies it to an internal registry, so downstream consumers pull from a controlled mirror. + +> [!NOTE] +> LTS tags may not yet be available in the registry. See the [Version Channels](#version-channels) note above for details. + +```shell +./falcon-container-sensor-pull.sh \ +--client-id \ +--client-secret \ +--type falcon-sensor \ +--version LTS \ +--copy myregistry.com/mynamespace +``` + #### Example downloading the Falcon DaemonSet sensor (unified) The following example will download the latest version of the Falcon DaemonSet sensor container image using the unified sensor and copy it to another registry. diff --git a/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh b/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh index 1ef62f4..ad176aa 100755 --- a/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh +++ b/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh @@ -23,6 +23,17 @@ Optional Flags: By default, the image name and tag are appended. Use --copy-omit-image-name and/or --copy-custom-tag to change that behavior. -v, --version Specify sensor version to retrieve from the registry + + Accepts version strings or channel keywords: + ------------------------------------------- + latest Latest sensor version (default) + N-1 One release prior to the latest + N-2 Two releases prior to the latest + LTS Latest LTS release + LTS-1 Previous LTS release + 7.33 Latest build of version 7.33.x + 7.33.0-18606 Specific sensor build + -p, --platform Specify sensor platform to retrieve, e.g., x86_64, aarch64 -t, --type Specify which sensor to download (Default: falcon-container) @@ -456,6 +467,90 @@ display_api_scopes() { esac } +# Extract clean tag strings from list_tags JSON output +extract_raw_tags() { + list_tags | awk ' + /^[[:space:]]*"[0-9]/ { + gsub(/^[[:space:]]*"/, "") + gsub(/"[[:space:]]*,?[[:space:]]*$/, "") + if (length($0) > 0) print $0 + } + ' +} + +# Resolve version channel keywords (latest, N-1, N-2, LTS, LTS-1) to version prefixes +resolve_version_channel() { + local input="$1" + local normalized all_tags major_minor_versions lts_tags lts_versions target_version + + normalized=$(echo "$input" | tr '[:upper:]' '[:lower:]') + + case "$normalized" in + latest) + echo "" + return 0 + ;; + n-1 | n-2 | lts | lts-1) + all_tags=$(extract_raw_tags) + if [ -z "$all_tags" ]; then + die "No tags found for sensor type: ${SENSOR_TYPE}" + fi + ;; + *) + # Not a channel keyword — pass through as-is + echo "$input" + return 0 + ;; + esac + + case "$normalized" in + n-1) + major_minor_versions=$(echo "$all_tags" | grep -iv -- "-lts" | + awk -F'.' '{ print $1"."$2 }' | sort -u -V) + if [ "$(echo "$major_minor_versions" | wc -l)" -lt 2 ]; then + die "Not enough versions available for N-1. Only $(echo "$major_minor_versions" | wc -l | tr -d ' ') major.minor version(s) found." + fi + target_version=$(echo "$major_minor_versions" | tail -2 | head -1) + ;; + n-2) + major_minor_versions=$(echo "$all_tags" | grep -iv -- "-lts" | + awk -F'.' '{ print $1"."$2 }' | sort -u -V) + if [ "$(echo "$major_minor_versions" | wc -l)" -lt 3 ]; then + die "Not enough versions available for N-2. Only $(echo "$major_minor_versions" | wc -l | tr -d ' ') major.minor version(s) found." + fi + target_version=$(echo "$major_minor_versions" | tail -3 | head -1) + ;; + lts) + lts_tags=$(echo "$all_tags" | grep -i -- "-lts") + if [ -z "$lts_tags" ]; then + die "No LTS versions found for sensor type: ${SENSOR_TYPE}" + fi + lts_versions=$(echo "$lts_tags" | awk -F'.' '{ print $1"."$2 }' | sort -u -V) + lts_line=$(echo "$lts_versions" | tail -1) + target_version=$(echo "$lts_tags" | grep "^${lts_line}\." | sort -V | tail -1) + ;; + lts-1) + lts_tags=$(echo "$all_tags" | grep -i -- "-lts") + if [ -z "$lts_tags" ]; then + die "No LTS versions found for sensor type: ${SENSOR_TYPE}" + fi + lts_versions=$(echo "$lts_tags" | awk -F'.' '{ print $1"."$2 }' | sort -u -V) + if [ "$(echo "$lts_versions" | wc -l)" -lt 2 ]; then + die "Not enough LTS versions available for LTS-1. Only $(echo "$lts_versions" | wc -l | tr -d ' ') LTS version(s) found." + fi + lts_line=$(echo "$lts_versions" | tail -2 | head -1) + target_version=$(echo "$lts_tags" | grep "^${lts_line}\." | sort -V | tail -1) + ;; + esac + + if [ -z "$target_version" ]; then + return 1 + fi + + echo "$target_version" + return 0 +} + # Smart version matching function match_sensor_version() { local requested_version="$1" @@ -464,14 +559,7 @@ match_sensor_version() { local version_pattern # Get all available tags by properly parsing JSON output from list_tags - all_tags=$(list_tags | awk ' - /^[[:space:]]*"[0-9]/ { - # Extract quoted tag (lines starting with version numbers), remove surrounding quotes and whitespace - gsub(/^[[:space:]]*"/, "") - gsub(/"[[:space:]]*,?[[:space:]]*$/, "") - if (length($0) > 0) print $0 - } - ') + all_tags=$(extract_raw_tags) if [ -z "$requested_version" ]; then # If no version specified, get the latest version @@ -859,9 +947,13 @@ if [ "${ERROR}" = "true" ]; then die "ERROR: ${CONTAINER_TOOL} login failed. Error message: ${error_message}" fi -#Get latest sensor version -set +e # Temporarily disable exit-on-error for version matching -LATESTSENSOR=$(match_sensor_version "$SENSOR_VERSION") +# Resolve channel keywords (latest, N-1, N-2, LTS, LTS-1) to version prefixes. +RESOLVED_VERSION=$(resolve_version_channel "$SENSOR_VERSION") + +# Get latest sensor version +# match_sensor_version returns 1 for "no match" — a soft failure we handle below. +set +e +LATESTSENSOR=$(match_sensor_version "$RESOLVED_VERSION") set -e # Re-enable exit-on-error # Check if version matching was successful @@ -871,6 +963,7 @@ if [ -z "$LATESTSENSOR" ]; then Available versions can be listed with: $0 --list-tags -t ${SENSOR_TYPE} Tips for version matching: + - Use channel keywords: -v latest, -v N-1, -v N-2, -v LTS, -v LTS-1 - Use exact version: -v 7.31.0 - Use partial version: -v 7.31 (matches latest 7.31.x) - Use major version: -v 7 (matches latest 7.x.x)