20. OAuth 2.0 Security

OAuth 2.0 lets you integrate Spring Cloud Skipper into Single Sign-on (SSO) environments. You can use the following OAuth2 Grant Types:

The REST endpoints can be accessed in two ways:

[Note]Note

When you set up authentication, we strongly recommended enabling HTTPS as well, especially in production environments.

You can turn on OAuth2 authentication by setting environment variables or by adding the following block to skipper.yml:

security:
  oauth2:
    client:
      client-id: myclient                                             1
      client-secret: mysecret
      access-token-uri: http://127.0.0.1:9999/oauth/token
      user-authorization-uri: http://127.0.0.1:9999/oauth/authorize
    resource:
      user-info-uri: http://127.0.0.1:9999/me

1

Providing the Client ID in the OAuth Configuration Section activates OAuth2 security.

You can verify that basic authentication is working properly by using curl, as follows:

$ curl -u myusername:mypassword localhost:7577/

As a result, you should see a list of available REST endpoints.

Besides Basic Authentication, you can also provide an Access Token to access the REST API. To make that happen, retrieve an OAuth2 Access Token from your OAuth2 provider and then pass that Access Token to the REST API by using the Authorization HTTP header, as follows:

$ curl -H "Authorization: Bearer <ACCESS_TOKEN>" localhost:7577/

20.1 OAuth REST Endpoint Authorization

Spring Cloud Skipper supports the following roles:

  • VIEW: For anything that relates to retrieving state.
  • CREATE: For anything that involves creating, deleting, or mutating the state of the system.
  • MANAGE: For boot management endpoints.

The rules regarding which REST endpoints require which roles are specified in the application.yml of the spring-cloud-skipper-server-core module.

Nonetheless, you can override those, if desired. The configuration takes the form of a YAML list (as some rules may have precedence over others). Consequently, you need to copy/paste the whole list and tailor it to your needs (as there is no way to merge lists). Always refer to your version of application.yml, as the snippet reproduced below may be outdated. The default rules are as follows:

            # About

            - GET /api/about                      => hasRole('ROLE_VIEW')

            # AppDeployerDatas

            - GET /api/appDeployerDatas           => hasRole('ROLE_VIEW')

            # Deployers

            - GET /api/deployers                  => hasRole('ROLE_VIEW')

            ## Releases

            - GET /api/releases                   => hasRole('ROLE_VIEW')

            # Status

            - GET /api/release/status/**         => hasRole('ROLE_VIEW')

            # Manifest

            - GET /api/release/manifest/**       => hasRole('ROLE_VIEW')

            # Upgrade

            - POST /api/release/upgrade          => hasRole('ROLE_CREATE')

            # Rollback

            - POST /api/release/rollback/**      => hasRole('ROLE_CREATE')

            # Delete

            - DELETE /api/release/**             => hasRole('ROLE_CREATE')

            # History

            - GET /api/release/history/**           => hasRole('ROLE_VIEW')

            # List

            - GET /api/release/list                         => hasRole('ROLE_VIEW')
            - GET /api/release/list/**                      => hasRole('ROLE_VIEW')

            # Packages

            - GET /api/packages                    => hasRole('ROLE_VIEW')

            # Upload

            - POST /api/package/upload             => hasRole('ROLE_CREATE')

            # Install

            - POST /api/package/install             => hasRole('ROLE_CREATE')
            - POST /api/package/install/**          => hasRole('ROLE_CREATE')

            # Delete

            - DELETE /api/package/**                => hasRole('ROLE_CREATE')

            # PackageMetaData

            - GET /api/packageMetadata              => hasRole('ROLE_VIEW')
            - GET /api/packageMetadata/**           => hasRole('ROLE_VIEW')

            # Repositories

            - GET /api/repositories                 => hasRole('ROLE_VIEW')
            - GET /api/repositories/**              => hasRole('ROLE_VIEW')

            # Boot Endpoints

            - GET  /actuator/**                     => hasRole('ROLE_MANAGE')

The format of each line is as follows:

HTTP_METHOD URL_PATTERN '⇒' SECURITY_ATTRIBUTE

where

Be mindful that the above is indeed a YAML list, not a map (thus the use of '-' dashes at the start of each line) that lives under the spring.cloud.skipper.security.authorization.rules key.

20.1.1 Users and Roles

Spring Cloud Skipper does not make any assumptions of how roles are assigned to users. Due to the fact that the determination of security roles is very environment-specific, Spring Cloud Data Skipper, by default, assigns all roles to authenticated OAuth2 users by using the DefaultAuthoritiesExtractor class.

You can customize that behavior by providing your own Spring bean definition that extends Spring Security OAuth’s AuthoritiesExtractor interface. In that case, the custom bean definition takes precedence over the default one provided by Spring Cloud Skipper.

20.2 OAuth Authentication Using the Spring Cloud Skipper Shell

If your OAuth2 provider supports the Password Grant Type, you can start the Skipper shell with the following command:

$ java -jar spring-cloud-skipper-shell-1.0.4.RELEASE.jar \
  --spring.cloud.skipper.client.serverUrl=http://localhost:7577 \
  --spring.cloud.skipper.client.username=my_username \
  --spring.cloud.skipper.client.password=my_password
[Note]Note

When authentication for Spring Cloud Skipper is enabled, the underlying OAuth2 provider must support the Password OAuth2 Grant Type if you want to use the hell.

From within the Skipper shell, you can also provide credentials by using the following command:

skipper:> skipper config --uri https://localhost:7577/api --username my_username --password my_password

Once successfully targeted, you should see the following output:

Successfully targeted http://localhost:7577/api
skipper:>

20.3 OAuth2 Authentication Examples

This section provides examples of some common security arrangements for Skipper:

20.3.1 Local OAuth2 Server

With Spring Security OAuth, you can create your own OAuth2 Server by using the following annotations:

  • @EnableResourceServer
  • @EnableAuthorizationServer

You can find a working example application at https://github.com/ghillert/oauth-test-server/.

To do so, clone the project, build it, and start it. Then configure Spring Cloud Skipper with the respective Client ID and Client Secret.

[Warning]Warning

Use this option only for development or demo purposes.

20.3.2 Authentication Using UAA

If you need to set up a production-ready OAuth provider, you may want to consider using the CloudFoundry User Account and Authentication (UAA) Server. While it is used by Cloud Foundry, it can also be used stand-alone. For more information see github.com/cloudfoundry/uaa.

20.3.3 Authentication using GitHub

If you would like to use an existing OAuth2 provider, here is an example for GitHub. First, you need to register a new application under your GitHub account at: https://github.com/settings/developers

[Note]Note

For the Authorization callback URL, enter Spring Cloud Skippers’s Login URL — for example, localhost:9393/login.

Configure Spring Cloud Skipper with the GitHub Client ID and Secret, as follows:

security:
  oauth2:
    client:
      client-id: your-github-client-id
      client-secret: your-github-client-secret
      access-token-uri: https://github.com/login/oauth/access_token
      user-authorization-uri: https://github.com/login/oauth/authorize
    resource:
      user-info-uri: https://api.github.com/user
[Important]Important

GitHub does not support the OAuth2 password grant type. As a result, you cannot use the Spring Cloud Skipper shell in conjunction with GitHub.