20. OAuth 2.0 Security

OAuth 2.0 allows you to integrate Spring Cloud Skipper into Single Sign On (SSO) environments. The following 3 OAuth2 Grant Types will be used:

The REST endpoints can be accessed using 2 ways:

[Note]Note

When authentication is set up, it is strongly recommended to enable HTTPS as well, especially in production environments.

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

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 will activate OAuth2 security

You can verify that basic authentication is working properly using curl:

$ curl -u myusername:mypassword http://localhost:7577/

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

Besides Basic Authentication, you can also provide an Access Token in order to access the REST Api. In order to make that happen, you would retrieve an OAuth2 Access Token from your OAuth2 provider first, and then pass that Access Token to the REST Api using the Authorization Http header:

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

20.1 OAuth REST Endpoint Authorization

Spring Cloud Skipper supports the following 3 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 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) and so you’ll 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 out-dated. The default rules are as such:

            # 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 the following:

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 fact that the determination of security roles is very environment-specific, Spring Cloud Data Skipper will by default assign all roles to authenticated OAuth2 users 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 will take 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:

$ java -jar spring-cloud-skipper-shell-1.0.0.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

Keep in mind that 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 Shell.

From within the Skipper Shell you can also provide credentials using:

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

20.3.1 Local OAuth2 Server

With Spring Security OAuth you can easily create your own OAuth2 Server with the following 2 simple annotations:

  • @EnableResourceServer
  • @EnableAuthorizationServer

A working example application can be found at:

https://github.com/ghillert/oauth-test-server/

Simply clone the project, built and start it. Furthermore configure Spring Cloud Skipper with the respective Client Id and Client Secret.

[Important]Important

Please use this option for development or demo purposes only.

20.3.2 Authentication using UAA

If you need to setup a production-ready OAuth provider, you may want to consider using the CloudFoundry User Account and Authentication (UAA) Server. 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 rather 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 you will enter Spring Cloud Skippers’s Login URL, e.g. localhost:9393/login.

Configure Spring Cloud Skipper with the GitHub relevant Client Id and Secret:

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 such you cannot use the Spring Cloud Skipper Shell in conjunction with GitHub.