Installation
16. Installing on a Local Platform
16.1. Local Platform configuration
The following example YAML file configures two local deployer accounts, named localDev
and localDevDebug
:
spring:
cloud:
skipper:
server:
platform:
local:
accounts:
localDev:
shutdownTimeout: 60
javaOpts: "-Dtest=foo"
localDevDebug:
javaOpts: "-Xdebug"
The key-value pairs that follow the name of the account are javaCmd
, workingDirectoriesRoot
, deleteFilesOnExit
, envVarsToInherit
, shutdownTimeout
, javaOpts
, and useSpringApplicationJson
.
More information can be found in the JavaDocs for LocalDeployerProperties.
17. Installing on Cloud Foundry
This section contains an example YAML file that configures two Cloud Foundry accounts, named cf-dev
and cf-qa
.
This is useful on Cloud Foundry if you use the Spring Cloud Config Server to manage Skipper’s configuration properties.
17.1. Cloud Foundry Configuration
You can modify the following sample YML snippet to fit your needs:
spring:
cloud:
skipper:
server:
platform:
cloudfoundry:
accounts:
cf-dev:
connection:
url: https://api.run.pivotal.io
org: myOrg
space: mySpace
domain: cfapps.io
username: [email protected]
password: drowssap
skipSslValidation: false
deployment:
memory: 2048m
disk: 2048m
services: rabbit
deleteRoutes: false
cf-qa:
connection:
url: https://api.run.pivotal.io
org: myOrgQA
space: mySpaceQA
domain: cfapps.io
username: [email protected]
password: drowssap
skipSslValidation: true
deployment:
memory: 1024m
disk: 1024m
services: rabbitQA
deleteRoutes: false
The deleteRoutes deployment setting is false so that “v2” of an application has the same route as “v1”.
Otherwise, undeploying “v1” removes the route.
|
You can also run the Skipper server locally and deploy to Cloud Foundry.
In this case, it is more convenient to specify the configuration in a skipper.yml
file and start the server with the --spring.config.additional-location=skipper.yml
option.
If you use cf push
to deploy Skipper, a Cloud Foundry manifest is more appropriate to use.
You can modify the following sample manifest.yml to fit your needs:
applications:
- name: mlp-skipper
host: mlp-skipper
memory: 1G
disk_quota: 1G
timeout: 180
instances: 1
buildpack: java_buildpack
path: spring-cloud-skipper-server.jar
env:
SPRING_APPLICATION_NAME: mlp-skipper
JBP_CONFIG_SPRING_AUTO_RECONFIGURATION: '{enabled: false}'
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_CONNECTION_URL: https://api.run.pivotal.io
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_CONNECTION_ORG: myOrgQA
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_CONNECTION_SPACE: mySpaceQA
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_CONNECTION_DOMAIN: cfapps.io
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_CONNECTION_USERNAME: [email protected]
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_CONNECTION_PASSWORD: drowssap
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_CONNECTION_SKIPSSLVALIDATION: false
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_DEPLOYMENT_DELETEROUTES: false
SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_DEPLOYMENT_SERVICES: rabbitmq
services:
- mysqlboost
In the preceding manifest, we bound the application to the mysqlboost service.
If you do not specify a service, the server uses an embedded database.
|
As of Skipper 2.0, you must disable Spring Auto-reconfiguration and set the profile to cloud .
|
You must set SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_DEPLOYMENT_DELETEROUTES: false so that “v2” of an application has the same route as “v1”.
Otherwise, undeploying “v1” removes the route.
|
You must set SPRING_CLOUD_SKIPPER_SERVER_PLATFORM_CLOUDFOUNDRY_ACCOUNTS[pws]_DEPLOYMENT_SERVICES property that binds the specified services to each of the deployed applications.
|
You can find information on the deployment properties that you can configure in CloudFoundryDeploymentProperties.
When starting the Skipper shell on your local machine, it tries to connect to the Server at the default location of localhost:7577/api
.
Use the shell’s --spring.cloud.skipper.client.serverUri
command line option to specify the location of the server.
You can alternatively use the config
interactive shell command to set the server location, as follows:
server-unknown:>skipper config --uri https://mlp-skipper.cfapps.io/api
Successfully targeted https://mlp-skipper.cfapps.io/api
skipper:>
17.2. Database Connection Pool
As of Skipper 2.0, the Spring Cloud Connector library is no longer used to create the DataSource. The library java-cfenv is now used which allows you to set Spring Boot properties to configure the connection pool.
17.3. Maximum Disk Quota
By default, every application in Cloud Foundry starts with 1G disk quota and this can be adjusted to a default maximum of 2G. The default maximum can also be overridden up to 10G by using Pivotal Cloud Foundry’s (PCF) Ops Manager GUI.
This configuration is relevant for Spring Cloud Skipper because every deployment is composed of applications (typically Spring Boot uber-jar’s), and those applications are resolved from a remote maven repository. After resolution, the application artifacts are downloaded to the local Maven Repository for caching and reuse. With this happening in the background, the default disk quota (1G) can fill up rapidly, especially when we experiment with streams that are made up of unique applications. In order to overcome this disk limitation and depending on your scaling requirements, you may want to change the default maximum from 2G to 10G. Let’s review the steps to change the default maximum disk quota allocation.
From PCF’s Ops Manager, select the “Pivotal Elastic Runtime” tile and navigate to the “Application Developer Controls” tab. Change the “Maximum Disk Quota per App (MB)” setting from 2048 (2G) to 10240 (10G). Save the disk quota update and click “Apply Changes” to complete the configuration override.
17.4. Managing Disk Use
Even when configuring Skipper to use 10G of space, there is the possibility of exhausting the available space on the local disk.
To prevent this, jar
artifacts downloaded from external sources, i.e., apps registered as http
or maven
resources, are automatically deleted whenever the application is deployed, whether or not the deployment request succeeds.
This behavior is optimal for production environments in which container runtime stability is more critical than I/O latency incurred during deployment.
In development environments deployment happens more frequently. Additionally, the jar
artifact (or a lighter metadata
jar) contains metadata describing application configuration properties
which is used by various operations related to application configuration, more frequently performed during pre-production activities.
To provide a more responsive interactive developer experience at the expense of more disk usage in pre-production environments, you can set the CloudFoundry deployer property autoDeleteMavenArtifacts
to false
.
If you deploy the Skipper by using the default port
health check type, you must explicitly monitor the disk space on the server in order to avoid running out space.
If you deploy the server by using the http
health check type (see the next example), the server is restarted if there is low disk space.
This is due to Spring Boot’s Disk Space Health Indicator.
You can configure the settings of the Disk Space Health Indicator by using the properties that have the management.health.diskspace
prefix.
For version 1.7, we are investigating the use of Volume Services for the server to store .jar
artifacts before pushing them to Cloud Foundry.
The following example shows how to deploy the http
health check type to an endpoint called /management/health
:
---
...
health-check-type: http
health-check-http-endpoint: /management/health
18. Installing on Kubernetes
A docker image, named springcloud/spring-cloud-skipper-server
, is available for Skipper server in dockerhub.
You can use this image to run the Skipper server in Kubernetes.
18.1. Kubernetes configuration
The following example YAML file configures two accounts, named k8s-dev
and k8sqa
, on a Kubernetes cluster.
spring:
cloud:
skipper:
server:
platform:
kubernetes:
accounts:
k8s-dev:
namespace: devNamespace
cpu: 4
k8s-qa:
namespace: qaNamespace
memory: 1024m
The accounts correspond to different namespaces. We are investigating how to support connecting to different Kubernetes clusters.
You can find more information on the deployment properties that you can configure in KubernetesDeployerProperties
19. Database configuration
A relational database is used to store stream definitions and deployment info. Spring Cloud Skipper provides schemas for MariaDB, MySQL, Oracle, PostgreSQL, Db2, SQL Server, and H2. The schema is automatically created when the server starts.
The JDBC drivers for MariaDB, MySQL (via the MariaDB driver), PostgreSQL, SQL Server are available without additional configuration. To use any other database you need to put the corresponding JDBC driver jar on the classpath of the server as described here. |
To configure a database the following properties must be set:
-
spring.datasource.url
-
spring.datasource.username
-
spring.datasource.password
-
spring.datasource.driver-class-name
The username
and password
are the same regardless of the database. However, the url
and driver-class-name
vary per database as follows.
Database | spring.datasource.url | spring.datasource.driver-class-name | Driver included |
---|---|---|---|
MariaDB 10.4+ |
jdbc:mariadb://${db-hostname}:${db-port}/${db-name} |
org.mariadb.jdbc.Driver |
Yes |
MySQL 5.7 |
jdbc:mysql://${db-hostname}:${db-port}/${db-name}?permitMysqlScheme |
org.mariadb.jdbc.Driver |
Yes |
MySQL 8.0+ |
jdbc:mariadb://${db-hostname}:${db-port}/${db-name}?allowPublicKeyRetrieval=true&useSSL=false&autoReconnect=true&permitMysqlScheme[1] |
org.mariadb.jdbc.Driver |
Yes |
PostgresSQL |
jdbc:postgres://${db-hostname}:${db-port}/${db-name} |
org.postgresql.Driver |
Yes |
SQL Server |
jdbc:sqlserver://${db-hostname}:${db-port};databasename=${db-name}&encrypt=false |
com.microsoft.sqlserver.jdbc.SQLServerDriver |
Yes |
DB2 |
jdbc:db2://${db-hostname}:${db-port}/{db-name} |
com.ibm.db2.jcc.DB2Driver |
No |
Oracle |
jdbc:oracle:thin:@${db-hostname}:${db-port}/{db-name} |
oracle.jdbc.OracleDriver |
No |
19.1. H2
When no other database is configured and the H2 driver has been added to the server classpath then Spring Cloud Skipper uses an embedded instance of the H2 database as the default.
H2 is good for development purposes but is not recommended for production use nor is it supported as an external mode. |
To use H2 add the com.h2database:h2:2.1.214
JDBC driver to the classpath and do not configure any other database.
19.2. Adding a Custom JDBC Driver
To add a custom driver for the database (for example, Oracle), you should rebuild the Skipper Server and add the dependency to the Maven pom.xml
file.
You need to modify the maven pom.xml
of spring-cloud-skipper
module.
There are GA release tags in GitHub repository, so you can switch to desired GA tags to add the drivers on the production-ready codebase.
To add a custom JDBC driver dependency for the Spring Cloud Skipper server:
-
Select the tag that corresponds to the version of the server you want to rebuild and clone the github repository.
-
Edit the spring-cloud-skipper-server/pom.xml and, in the
dependencies
section, add the dependency for the database driver required. In the following example , an Oracle driver has been chosen:
<dependencies>
...
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1</version>
</dependency>
...
</dependencies>
-
Build the application as described in Building Spring Cloud Skipper = Security
By default, the Spring Cloud Skipper server is unsecured and runs on an unencrypted HTTP connection. You can secure your REST endpoints by enabling HTTPS and requiring clients to authenticate using OAuth 2.0
By default, the REST endpoints (administration, management and health) do not require authenticated access. |
20. Enabling HTTPS
By default, the REST endpoints use plain HTTP as a transport.
You can switch to HTTPS by adding a certificate to your configuration, as shown in the following skipper.yml
example:
server:
port: 8443 (1)
ssl:
key-alias: yourKeyAlias (2)
key-store: path/to/keystore (3)
key-store-password: yourKeyStorePassword (4)
key-password: yourKeyPassword (5)
trust-store: path/to/trust-store (6)
trust-store-password: yourTrustStorePassword (7)
1 | As the default port is 7577 , you may choose to change the port to a more common HTTPs-typical port. |
2 | The alias (or name) under which the key is stored in the keystore. |
3 | The path to the keystore file. Classpath resources may also be specified, by using the classpath prefix: classpath:path/to/keystore |
4 | The password of the keystore. |
5 | The password of the key. |
6 | The path to the truststore file. Classpath resources may also be specified, by using the classpath prefix: classpath:path/to/trust-store |
7 | The password of the trust store. |
You can reference the YAML file using the following parameter: --spring.config.additional-location=skipper.yml
|
If HTTPS is enabled, it completely replaces HTTP as the protocol over which the REST endpoints interact. Plain HTTP requests then fail. Therefore, you must make sure that you configure the Skipper shell accordingly. |
20.1. Using Self-Signed Certificates
For testing purposes or during development, it might be convenient to create self-signed certificates. To get started, run the following command to create a certificate:
$ keytool -genkey -alias skipper -keyalg RSA -keystore skipper.keystore \
-validity 3650 -storetype JKS \
-dname "CN=localhost, OU=Spring, O=Pivotal, L=Holualoa, ST=HI, C=US" (1)
-keypass skipper -storepass skipper
1 | CN is the only important parameter here. It should match the domain you are trying to access, e.g. localhost . |
Then add the following to your skipper.yml
file:
server:
port: 8443
ssl:
enabled: true
key-alias: skipper
key-store: "/your/path/to/skipper.keystore"
key-store-type: jks
key-store-password: skipper
key-password: skipper
That is all you need for the Skipper Server. Once you start the server, you should be able to access it at https://localhost:8443/. As this is a self-signed certificate, you should hit a warning in your browser. You need to ignore that.
20.2. Self-Signed Certificates and the Shell
By default, self-signed certificates are an issue for the shell. Additional steps are necessary to make the shell work with self-signed certificates. Two options are available:
20.2.1. Add the Self-signed Certificate to the JVM Truststore
In order to use the JVM truststore option, we need to export the previously created certificate from the keystore:
$ keytool -export -alias skipper -keystore skipper.keystore -file skipper_cert -storepass skipper
Next, we need to create a truststore which the Shell uses:
$ keytool -importcert -keystore skipper.truststore -alias skipper -storepass skipper -file skipper_cert -noprompt
Now you can launch the Skipper shell by using the following JVM arguments:
$ java -Djavax.net.ssl.trustStorePassword=skipper \
-Djavax.net.ssl.trustStore=/path/to/skipper.truststore \
-Djavax.net.ssl.trustStoreType=jks \
-jar spring-cloud-skipper-shell-2.11.5.jar
If you run into trouble establishing a connection over SSL, you can enable additional logging by setting the javax.net.debug JVM argument to ssl .
|
Remember to target the Skipper server with a config command similar to the following:
skipper:>skipper config --uri https://localhost:8443/api
20.2.2. Skip Certificate Validation
Alternatively, you can bypass the certification validation by providing the following optional command-line parameter: --spring.cloud.skipper.client.skip-ssl-validation=true
.
When you set this command-line parameter, the shell accepts any (self-signed) SSL certificate.
If possible, you should avoid using this option. Disabling the trust manager defeats the purpose of SSL and makes your site vulnerable to man-in-the-middle attacks. |
21. 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:
-
Password: Used by the shell (and the REST integration), so you can login with a username and a password
-
Client Credentials: Retrieve an Access Token directly from your OAuth provider and pass it to the Skipper server in the
Authorization
HTTP header.
The REST endpoints can be accessed in two ways:
-
Basic Authentication: Uses the Password Grant Type to authenticate with your OAuth2 service.
-
Access Token: Uses the Client Credentials Grant Type
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
spring:
security:
oauth2: (1)
client:
registration:
uaa: (2)
client-id: myclient
client-secret: mysecret
redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
authorization-grant-type: authorization_code
scope:
- openid (3)
provider:
uaa:
jwk-set-uri: http://uaa.local:8080/uaa/token_keys
token-uri: http://uaa.local:8080/uaa/oauth/token
user-info-uri: http://uaa.local:8080/uaa/userinfo (4)
user-name-attribute: user_name (5)
authorization-uri: http://uaa.local:8080/uaa/oauth/authorize
resourceserver:
opaquetoken:
introspection-uri: http://uaa.local:8080/uaa/introspect (6)
client-id: dataflow
client-secret: dataflow
cloud:
skipper:
security:
authorization:
provider-role-mappings: (7)
uaa:
map-oauth-scopes: true
role-mappings:
ROLE_VIEW: skipper.view
ROLE_CREATE: skipper.create
ROLE_MANAGE: skipper.manage
1 | Providing this property activates OAuth2 security |
2 | The provider id. It is possible to specify more than 1 provider |
3 | As the UAA is an OpenID provider, you must at least specify the openid scope.
If your provider also provides additional scopes to control the role assignments,
you must specify those scopes here as well |
4 | OpenID endpoint. Used to retrieve user information such as the username. Mandatory. |
5 | The JSON property of the response that contains the username |
6 | Used to introspect and validate a directly passed-in token. Mandatory. |
7 | Role mappings for authorization.
You can verify that basic authentication is working properly by using curl , as follows: |
`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 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>" http://localhost:7577/
21.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
-
HTTP_METHOD is one http method, capital case.
-
URL_PATTERN is an Ant-style URL pattern.
-
SECURITY_ATTRIBUTE is a SpEL expression (see docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#el-access)
-
Each of those parts is separated by one or several white space characters (spaces, tabs, and others).
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.
21.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.
21.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-2.11.5.jar \
--spring.cloud.skipper.client.serverUrl=http://localhost:7577 \
--spring.cloud.skipper.client.username=my_username \
--spring.cloud.skipper.client.password=my_password
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:>
21.3. OAuth2 Authentication Examples
This section provides examples of some common security arrangements for Skipper:
21.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.
Use this option only for development or demo purposes. |
21.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.