Skip to content

ECLI-013: Buildkite writes Cloud admin key to config file without 0600 permission or cleanup #519

Description

@margaretjgu

Severity: Medium

Problem

.buildkite/setup-env.sh:18–38 writes the Vault-sourced Cloud API key to ~/.elasticrc.yml using shell redirection:

cat > "$HOME/.elasticrc.yml" <<EOF
...
EOF

With umask 022, a new file is 0644 and readable by other OS users on the agent. Redirection preserves the mode of an existing file. The script never removes the file, so the credential remains on a shared or reused agent until cleanup or recycling. Because the script is sourced (.buildkite/run-cloud-tests.sh:35), EC_API_KEY also remains in the calling shell.

0600 narrows exposure to other OS users only — every process running as the same user can still read the file. Same-UID isolation requires ephemeral or dedicated agents (ECLI-014), not file permissions.

Fix

CI_CONFIG_DIR=$(mktemp -d)
chmod 0700 "$CI_CONFIG_DIR"

CI_CONFIG_FILE="$CI_CONFIG_DIR/config.json"
install -m 0600 /dev/null "$CI_CONFIG_FILE"

cleanup_cloud_config() {
  rm -f "$CI_CONFIG_FILE"
  rmdir "$CI_CONFIG_DIR" 2>/dev/null || true
}
trap cleanup_cloud_config EXIT

EC_API_KEY=$(vault read -field=api_key "$CLOUD_CREDENTIALS_PATH")

if [[ -z "$EC_API_KEY" || "$EC_API_KEY" == *$'\n'* ]]; then
  echo "Vault returned an invalid Cloud API key" >&2
  return 1
fi

printf '%s' "$EC_API_KEY" | node -e '
  const key = require("node:fs").readFileSync(0, "utf-8")
  process.stdout.write(JSON.stringify({
    contexts: { ci: { cloud: {
      url: "https://admin.qa.cld.elstc.co",
      auth: { api_key: key },
    } } },
    current_context: "ci",
  }))
' > "$CI_CONFIG_FILE"

unset EC_API_KEY
export ELASTIC_CLI_CONFIG_FILE="$CI_CONFIG_FILE"

JSON serialization prevents YAML injection; stdin keeps the key out of argv and exported environment variables; unset shortens its lifetime in the sourcing shell. The temporary config contains no resolvers and is 0600 inside a CI-owned 0700 directory, making it compatible with ECLI-016/ECLI-023.

Risk

Medium. A 0644 file containing a Cloud management-plane key is readable by other OS users and remains after the job. Mode 0600 removes cross-user access but not same-UID access.


Copied from the security review in elastic/infosec#27626 (ECLI-013).

Metadata

Metadata

Assignees

Labels

securitySecurity related

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions