Concourse CI is the pipeline platform that Pivotal built for its own use, then open-sourced, and that now runs inside a specific subset of platform engineering teams who value its explicit, data-flow-oriented pipeline model. The learning curve is steeper than Jenkins or GitLab CI, but once a team is fluent in Concourse, the pipelines tend to be easier to reason about than their equivalents in more imperative systems. Concourse's security model reflects that same explicit design — the primitives are narrow and composable, and the hardening story is about configuring those primitives correctly rather than disabling unsafe defaults.
This post covers Concourse CI hardening as it stands in release 7.11, the current version at the time of writing. It focuses on resource type trust, worker isolation, team-level RBAC, and the var source security that underpins the platform's multi-tenancy model. It is written for teams already running Concourse and looking to harden their installation, not for teams evaluating whether to adopt it.
The resource type model and its trust implications
Concourse pipelines are built from resources (versioned external artifacts) and jobs (sequences of steps that consume and produce resources). Resources have types — git, s3, semver, docker-image, and so on — and each resource type is implemented by a container image that Concourse runs to check, get, or put the resource.
This is where the trust model begins. A resource type container runs on a Concourse worker with access to whatever credentials the pipeline's resource specification provides. A malicious resource type implementation can exfiltrate those credentials, modify the resources it produces, or use the worker's network access to reach internal services.
The hardening pattern is to maintain an allow-list of approved resource types, to pin every resource type to a specific image digest, and to audit resource type definitions on a schedule. Concourse 7 introduced the concept of globally-configured resource types at the team level, which means an admin can define the approved resource type images once and restrict pipelines to those. The alternative — letting every pipeline specify its own resource type image — is what most new installations default to, and it is the source of the most common supply chain risks.
A production team-level resource type configuration looks like:
resource_types:
- name: git
type: registry-image
source:
repository: concourse/git-resource
tag: 1.16.0@sha256:a1b2c3...
- name: s3
type: registry-image
source:
repository: concourse/s3-resource
tag: 1.3.0@sha256:d4e5f6...
- name: semver
type: registry-image
source:
repository: concourse/semver-resource
tag: 1.6.0@sha256:g7h8i9...
With these configured at the team level and the team's pipelines restricted to the defined types, the pipeline authors cannot introduce a new resource type without platform team review, which is the correct control model.
Worker isolation and container runtime
Concourse workers execute pipeline jobs in containers. The default container runtime is containerd, and the isolation is container-level, which is standard for the class of tools. The specific configuration that matters is whether the workers run as dedicated per-team resources or as a shared pool.
The default configuration in a new Concourse installation is a shared worker pool. Every team's jobs can land on any worker, which means a worker that has cached a team's private git credentials (because it recently ran a git-resource for that team) can be used by another team's pipeline to read those cached credentials. The worker's on-disk state is not as ephemeral as the pipeline model suggests, because Concourse caches resource versions for performance.
The hardening pattern is to use per-team worker tags. Workers are tagged with team names, and pipelines specify which tags they require. Jobs then land only on workers with matching tags, which gives each team effective dedicated compute. The operational cost is that you provision more workers than a shared pool would require, but the isolation is meaningful for any environment where teams have different trust boundaries.
Concourse 7.10 added a rootless container mode that reduces the privilege level of pipeline containers. Enabling rootless mode is a defense-in-depth step that helps contain a container escape if one occurs. It is not enabled by default because it requires specific kernel features and has some compatibility considerations with older resource type implementations.
Team-level RBAC and the main team problem
Concourse's multi-tenancy primitive is the team. Each team has its own set of pipelines, credentials, and members, and the team is the security boundary for most of the platform's access controls. The main team exists by default and has administrative privileges over the entire Concourse installation.
The hardening pattern for the main team is to treat its membership as cluster-admin-equivalent. Members of the main team can create new teams, modify their configurations, and access credentials in any team. The main team should have a minimal membership — typically the platform team that operates Concourse — and non-platform users should be members of specific non-main teams.
Beyond the main team, team membership is typically configured through an external identity provider. Concourse supports GitHub, LDAP, OIDC, and a few other providers, and team membership is mapped from IdP groups. The standard practice is to map each Concourse team to one or more groups in the IdP, with the group membership managed there rather than in Concourse directly. This keeps the authorization decisions in one place and makes offboarding straightforward.
CVE-2022-45391 and similar advisories have highlighted that the authentication and team-mapping code in Concourse has the kind of complexity that produces occasional bugs. Keeping the Concourse version current is the standard mitigation, and the Concourse release cadence of roughly every two months is manageable.
Var sources and the credential story
Concourse var sources are the mechanism for injecting secrets into pipelines. A var source is a connection to an external secret manager — Vault, AWS SSM Parameter Store, Kubernetes Secrets, or CredHub — and pipelines reference variables by name in their YAML, with the actual secret values resolved at runtime from the configured source.
The security benefit of var sources is that secrets do not live in pipeline YAML or in Concourse's own storage. The secret manager is the source of truth, and Concourse fetches secret values at build time. This is the correct architecture, and it depends on the var source being configured correctly.
The specific hardening points are the authentication the var source uses to fetch secrets and the scope of secrets each team's var source can access. The Vault integration supports AppRole authentication and policy-scoped tokens. The AWS SSM integration supports IAM role authentication. The secret path for each team should be scoped so that team-A's var source cannot read team-B's secrets even if it attempts to.
A common misconfiguration is using a single shared Vault policy for all teams, with secrets at paths like concourse/team-a/secret-name. If the Vault policy is scoped to concourse/*, any team's var source can read any other team's secrets. Scoping the policies to concourse/team-a/* per team is the correct configuration, and it requires setting up one Vault role per Concourse team.
The web API and webhook surface
Concourse exposes a web API that is used by the fly CLI for authenticated operations. The API should not be publicly exposed without authentication in any configuration — the default installation requires authentication — but the authentication mechanism and session timeout should be reviewed.
Webhook triggers for resources are supported via the webhook_token field on a resource configuration. A resource with a webhook token can be checked on-demand by an external system, which is how Concourse integrates with git forge webhooks. The token is shared between Concourse and the webhook source, and if it leaks, an attacker can trigger resource checks at arbitrary times. This is not a critical risk for most resource types, but for resource types that interact with external services in ways that could be abused, rotating webhook tokens on a schedule is a reasonable practice.
How Safeguard Helps
Safeguard integrates with Concourse CI by ingesting the pipeline configurations across your teams, flagging resource types that are not on the approved allow-list, team configurations that lack per-team worker isolation, and var source configurations with overly broad secret paths. The platform also correlates the installed Concourse version against the current CVE feed, tracks artifact provenance from Concourse jobs into downstream deployment pipelines, and provides an auditable record of team membership changes. Combined with continuous policy evaluation of the pipeline YAML against your organization's hardening standards, Safeguard gives you a defensible supply chain posture for a platform whose security model rewards explicit configuration and whose defaults do not always match production-grade expectations.