Every pipeline and one-off build belongs to a team.
A team is simply a conceptual owner and a separate namespace for data in Concourse (pipelines, builds, etc.) with its own auth configuration. A team may map to GitHub oAuth, basic auth, UAA auth, or whatever other auth methods we add in the future.
Importantly, a team does not have "users" added to and removed from it; it's only a configuration of auth methods, which themselves may provide user info that we add semantics to in the future (i.e. which GitHub user you authorized as).
Out of the box, Concourse comes with a single team called
main team is an admin team, meaning it can create and update other teams. Currently there is no way to promote a team to become an admin team, so
main is a special-case.
main team is configured as part of the deployment itself as flags passed to the ATC. Changes to these flags take effect whenever the ATC starts up. This is so that you can't get locked out, and so that you can have Concourse sanely configured as soon as it comes up.
$ fly set-team -n my-team \ --basic-auth-username ci \ --basic-auth-password changeme
Once the team has been created, you can use
login to log in:
$ fly login -n my-team
Any newly configured pipelines (via
set-pipeline) and one-off builds (via
execute) will be owned by the authorized team. Commands that list content will be scoped to the current team by default, such as
builds. The web UI should reflect the same state.
Newly configured pipelines are hidden by default, meaning other teams and unauthorized visitors cannot view them. To make them publicly viewable, see Pipeline and build visibility.
Continuous Integration servers often contain a considerable number of secrets to let them access source code and deploy applications. It is important that those secrets remain well guarded. Concourse provides options for both authentication and authorization to give you control over who can access your server and how much they can see.
If you access your Concourse server over the public internet then all of the options below are useless without using TLS to secure your connection.
Any number of the following providers can be enabled at any one time. Users will be given a choice when logging in as to which one they would like to use.
HTTP Basic authentication is the simplest of the authentication mechanisms. It has good support in both browsers and command line tools. It provides a single set of credentials for all users of the system.
You can configure basic auth for a team via the
$ fly set-team -n my-team \ --basic-auth-username foo \ --basic-auth-password bar
A Concourse server can authenticate against GitHub to take advantage of their permission model and other security improvements in their infrastructure. There are a number of steps you need to take to enable this.
Configuring the GitHub oAuth for our own team of engineers at Pivotal may look something like:
$ fly set-team -n concourse \ --github-auth-client-id $CLIENT_ID \ --github-auth-client-secret $CLIENT_SECRET \ --github-auth-team concourse/Pivotal
First you need to create an OAuth application on GitHub.
The name, home page, and description don't matter but should be set to something that lets users trust their origin. The Authorization callback URL should be the external URL of your Concourse server with
/auth/github/callback appended. For example, Concourse's own CI server's callback URL is
You will be given a Client ID and a Client Secret for your new application. These will then be passed to the following flags:
If you're configuring GitHub Enterprise, you'll also need to set the following flags:
Make sure the API URL ends with a slash!
--uaa-auth-* flags allow you to authorize members of a particular space in a CF deployment. In the future we'll make this generic to UAA and request scopes.
You'll first need to configure a client for Concourse with your UAA. The callback URL will be the external URL of your Concourse server with
/auth/oauth/callback appended. For example, Concourse's own CI server's callback URL would be
The client should look something like this, under
concourse: id: my-client-id secret: my-client-secret scope: cloud_controller.read authorities: cloud_controller.admin authorized-grant-types: "authorization_code,client_credentials,refresh_token" access-token-validity: 3600 refresh-token-validity: 3600 autoapprove: true override: true redirect-uri: https://concourse.example.com/auth/uaa/callback
Configuring auth for my team's space in a CF installation may look something like:
$ fly set-team -n my-cf-team \ --uaa-auth-client-id $CLIENT_ID \ --uaa-auth-client-secret $CLIENT_SECRET \ --uaa-auth-auth-url https://login.my-cf.com/oauth/authorize \ --uaa-auth-token-url https://login.my-cf.com/oauth/token \ --uaa-auth-cf-url https://api.my-cf.com \ --uaa-auth-cf-ca-cert ./path/to/cf-ca-cert.crt \ --uaa-auth-cf-space 31d89184-35b8-4660-a8ab-a7f72cc24435
31d89184-35b8-4660-a8ab-a7f72cc24435 value above is the GUID of the space whose members will be authorized.
--generic-oauth-* flags configure a generic oAuth provider which performs no additional verification about the individual user signing in by default. It should only be used with internal auth systems in this way. If it were used to configure Google or Twitter oAuth, for example, it would permit just about every person on the internet to create pipelines. It'd be mighty generous. If you need verification, make sure you are using the
You'll first need to configure the client with your oAuth provider. The callback URL will be the external URL of your Concourse server with
/auth/oauth/callback appended. For example, Concourse's own CI server's callback URL would be
Configuring generic oAuth for X company's internal oAuth service may look something like:
$ fly set-team -n my-team-in-x \ --generic-oauth-display-name 'X' \ --generic-oauth-client-id $CLIENT_ID \ --generic-oauth-client-secret $CLIENT_SECRET \ --generic-oauth-auth-url https://oauth.example.com/o/oauth2/auth \ --generic-oauth-token-url https://oauth.example.com/o/oauth2/token
You can also pass arbitrary params, for example a
scope to request, like so:
$ fly set-team -n my-team-in-x \ --generic-oauth-display-name 'X' \ --generic-oauth-client-id $CLIENT_ID \ --generic-oauth-client-secret $CLIENT_SECRET \ --generic-oauth-auth-url https://oauth.example.com/o/oauth2/auth \ --generic-oauth-token-url https://oauth.example.com/o/oauth2/token \ --generic-oauth-auth-url-param scope:read
--generic-oauth-auth-url-param flag can be specified multiple times to configure multiple params, in the form of
If you need verification of users, you can choose to require users have a particular scope with
$ fly set-team -n my-team-in-x \ --generic-oauth-display-name 'X' \ --generic-oauth-client-id $CLIENT_ID \ --generic-oauth-client-secret $CLIENT_SECRET \ --generic-oauth-auth-url https://oauth.example.com/o/oauth2/auth \ --generic-oauth-token-url https://oauth.example.com/o/oauth2/token \ --generic-oauth-scope concourse.main
Given that this is a catch-all provider, there may be things that go wrong that we can't really document in great detail. If things aren't working, try flailing until it works.
For example, some providers seem to expect values like
client_secret to be specified as query params on the token URL. Our oAuth2 library sends these values as the request payload POSTed to the endpoint instead. In this case you could try tacking the query params on to the end of the token URL like so:
$ fly set-team -n my-team-in-x \ --generic-oauth-display-name 'X' \ --generic-oauth-client-id $CLIENT_ID \ --generic-oauth-client-secret $CLIENT_SECRET \ --generic-oauth-auth-url https://oauth.example.com/o/oauth2/auth \ --generic-oauth-token-url \ "https://oauth.example.com/o/oauth2/token?client_secret=$CLIENT_SECRET" \ --generic-oauth-auth-url-param scope:some-scope
Pretty janky but it works.
We've written the authentication layer of Concourse to be easily extendable. Adding a new OAuth provider is as simple as adding a few interface implementations and feeding them any information they need from the command line.
We'd be interested in hearing about any providers with which you'd like to integrate.
Every newly configured pipeline is hidden to anyone but the pipeline's team. To make a pipeline publicly viewable, both by other teams and unauthenticated users, see
Even with a pipeline exposed, all build logs are hidden by default. This is because CI jobs are prone to leaking credentials and other...unsavory information. After you've determined that a job's builds should be safe for public consumption, you can set
public: true on the job in your pipeline.
At present, teams only provide trusted multi-tenancy. This means it should be used for cases where you know and trust who you're allowing access into your Concourse cluster.
There are a few reasons it'd be a bad idea to do otherwise:
Any team can run
privilegedbuilds. A bad actor in the mix could easily use this to harm your workers and your cluster.
In the future, we'll probably have this as a flag on a team, indicating whether they're permitted to run privileged builds.
There are no networking restrictions in place, and traffic to and from the workers is currently unencrypted and unauthorized. Anyone could run a task that does horrible things to your worker's containers, possibly stealing sensitive information.
This can be remedied with configuration specified on Garden to restrict access to the internal network, but this is not detailed in our docs, and we'll probably want to find a better answer than configuration in the future.