Configuring Application Configuration Service for VMware Tanzu

This topic describes how to define resources for Application Configuration Service for VMware Tanzu (ACS). The first part of this document will describe different ways to define a ClusterConfigProvider resource. After that, the document will describe how to define a ConfigurationSlice.

Defining Configuration Providers

The simplest form of a ClusterConfigProvider will have a single source of properties, a reference to a Git repository. The following example shows a manifest to create such a resource:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ClusterConfigProvider
metadata:
  name: cook-config-provider
spec:
  backends:
    - type: git
      uri: https://github.com/spring-cloud-services-samples/cook-config

The metadata.name parameter specifies the name to be given to the ClusterConfigProvider. This can be anything you like, but you’ll need to remember it so that it can be referenced when creating a ConfigurationSlice resource.

Under spec, the backends property is a list of property source backends from which configuration may be obtained. In this case, it is a single Git repository whose URL refers to a Git repository at https://github.com/spring-cloud-services-samples/cook-config.

If you’d like to configure additional Git backends, you can simply add more entries to the backends list. For example:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ClusterConfigProvider
metadata:
  name: cook-config-provider
spec:
  backends:
    - type: git
      uri: https://github.com/spring-cloud-services-samples/cook-config
    - type: git
      uri: https://github.com/myorg/config-repo
    - type: git
      uri: https://github.com/another/another-config-repo

To create the ClusterConfigProvider resource, use kubectl apply as follows:

$ kubectl apply -f my-config-provider.yaml

While the YAML above presents the simplest ClusterConfigProvider definition, the remainder of this section describes additional configuration options available when creating a ClusterConfigProvider.

Backend Configuration Overview

Parameters used to configure configuration backends are part of the backends entry in the YAML manifest for a ClusterConfigProvider. The type parameter should be set to “git” for a Git configuration source. General parameters used to configure the ClusterConfigProvider’s default configuration source are listed below.

Parameter Function
type The type of backend. Currently only “git” is supported. Required
uri The URI (http://, https://, or git@example.com…) of a Git repository. Required
defaultLabel The default “label” used if a request is received without a label. Default value: master
searchPaths A pattern used to search for configuration-containing subdirectories in the repository
skipSslValidation For a https:// URI, whether to skip validation of the SSL certificate on the repository’s server. Valid values: true, false
credentialsRef The name of a Secret resource containing credentials and keys for accessing the Git repository
credentialsRefNamespace The namespace where the Secret specified in credentialsRef may be found

Setting a Default Label

By default, configuration pulled from the backends in a ClusterConfigProvider comes from the “master” branch, unless specified otherwise in a ConfigurationSlice.

You can override the default label by setting the defaultLabel property, setting it to a branch name, a tag name, or a specific Git commit hash. To set defaultLabel to point to the develop branch of a repository, you might define the ClusterConfigProvider as follows:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ClusterConfigProvider
metadata:
  name: cook-config-provider
spec:
  backends:
    - type: git
      uri: https://github.com/spring-cloud-services-samples/cook-config
      defaultLabel: v1.1

Setting Search Paths

By default configuration pulled from the Git backends defined in a ClusterConfigProvider come from the root of the specified repositories. But you can set the searchPaths to specify a different path from which properties should be obtained:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ClusterConfigProvider
metadata:
  name: cook-config-provider
spec:
  backends:
    - type: git
      uri: https://github.com/spring-cloud-services-samples/cook-config
      searchPaths: configuration

In this example, configuration will be pulled from files in the directory at the path “/configuration”.

Skipping SSL Validation

By default, the SSL certificates from backend servers are validated. But you can set the skipSslValidation property to “true” to skip SSL validation:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ClusterConfigProvider
metadata:
  name: cook-config-provider
spec:
  backends:
    - type: git
      uri: https://github.com/spring-cloud-services-samples/cook-config
      skipSslValidation: true

Referencing Credentials and Keys

In many cases, access to configuration details in a backend repository will require authentication credentials, keys, and other data that should be maintained under greater secrecy than in the manifest for the ClusterConfigProvider. For those cases, you’ll need to create a Secret resource and configure the ClusterConfigProvider to reference the Secret.

The Secret referenced from a ClusterConfigProvider may contain one or more of the following entries:

Secret Entry Function
basicauth.username The username used to access the repository (if protected by HTTP Basic authentication)
basicauth.password The password used to access the repository (if protected by HTTP Basic authentication)
ssh.hostKey The host key of the Git server. If you have connected to the server via git on the command line, this is in your .ssh/known_hosts. Do not include the algorithm prefix; this is specified in hostKeyAlgorithm.
ssh.hostKeyAlgorithm The algorithm of hostKey: one of “ssh-dss”, “ssh-rsa”, “ecdsa-sha2-nistp256”, “ecdsa-sha2-nistp384”, and “ecdsa-sha2-nistp521”. (Required if supplying hostKey.)
ssh.privateKey The private key that identifies the Git user, with all newline characters replaced by \n. Passphrase-encrypted private keys are not supported.
ssh.privateKeyPassphrase The passphrase for the private key specified in ssh.privateKey
ssh.strictHostKeyChecking Whether or not the backend should be ignored it encounters an error when using the provided hostKey. (Optional.) Valid values are true and false. Default is true.
proxy.http.host The HTTP proxy host
proxy.http.port The HTTP proxy port
proxy.http.username The username to use with an authenticated HTTP proxy
proxy.http.password The password to use with an authenticated HTTP proxy
proxy.https.host The HTTPS proxy host
proxy.https.port The HTTPS proxy port
proxy.https.username The username to use with an authenticated HTTP proxy
proxy.https.password The password to use with an authenticated HTTP proxy
encryption.key The encryption key for decrypting properties prefixed with {cipher}

To define a Secret defining backend credentials, start by creating a YAML file containing the manifest for the Secret. For example, the following specifies HTTP Basic authentication:

apiVersion: v1
kind: Secret
metadata:
  name: git-secret
stringData:
  basicauth.username: someuser
  basicauth.password: somepassword

Then apply the Secret manifest using kubectl apply:

$ kubectl apply -f git-secret.yaml

This will create a Secret resource named “git-secret” that can then be referenced in the ClusterConfigProvider manifest in the credentialsRef parameter like this:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ClusterConfigProvider
metadata:
  name: cook-config-provider
spec:
  backends:
    - type: git
      uri: https://github.com/spring-cloud-services-samples/cook-config
      credentialsRef: git-secret

SSH Repository Access

You can configure a configuration provider backend so that it the Git backend is accessed using the Secure Shell (SSH) protocol. To do so, you must specify a URI using the Secure Copy Protocol (SCP) style URI format in the ClusterConfigProvider manifest.

A SSH URI must include a username, host, and repository path. This might be specified as shown in the following YAML:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ClusterConfigProvider
metadata:
  name: cook-config-provider
spec:
  backends:
    - type: git
      uri: git@github.com:spring-cloud-services-samples/cook-config.git
      credentialsRef: git-secret

You must also supply a private key in the Secret referenced in the credentialsRef parameter and the private key’s passphrase. You may also supply a host key with which the server will be identified. If you do not provide a host key, the host key of the configuration source’s server will not be validated.

For the referenced Secret, specify the SSH details like this to include SSH host key validation:

apiVersion: v1
kind: Secret
metadata:
  name: git-secret
stringData:
  basicauth.username: someuser
  basicauth.password: somepassword
  ssh.hostKey: EXAMPLEcccc1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+...
  ssh.hostKeyAlgorithm: ssh-rsa
  ssh.privateKey: -----BEGIN EXAMPLE RSA PRIVATE KEY-----\nMIIJKQIB...
  ssh.privateKeyPassphrase: s3cr3tP4$$phr4$3

To access a configuration source, without host key verification, use the following YAML for the Secret definition:

apiVersion: v1
kind: Secret
metadata:
  name: git-secret
stringData:
  basicauth.username: someuser
  basicauth.password: somepassword
  ssh.privateKey: -----BEGIN EXAMPLE RSA PRIVATE KEY-----\nMIIJKQIB...
  ssh.privateKeyPassphrase: s3cr3tP4$$phr4$3

HTTP(S) Proxy Repository Access

You can configure a ClusterConfigProvider resource to allow for accessing configuration sources using an HTTP or HTTPS proxy. To do so, you must provide proxy settings in either or both of the proxy.http.* or proxy.https.* objects in YAML. You can set the proxy host and port, and the proxy username and password (if applicable).

Note: If you are using multiple Git repositories that are accessed using the same proxy, you must provide the proxy’s settings for each Git backend.

To configure the ClusterConfigProvider with HTTP proxy details to access configuration sources, use the following YAML when defining the credentials Secret:

apiVersion: v1
kind: Secret
metadata:
  name: git-secret
stringData:
  basicauth.username: someuser
  basicauth.password: somepassword
  http.host: proxy.sample.com
  http.port: 80

To configure the ClusterConfigProvider with authenticated HTTPS proxy details to access configuration sources, use the following YAML when defining the credentials Secret:

apiVersion: v1
kind: Secret
metadata:
  name: git-secret
stringData:
  basicauth.username: someuser
  basicauth.password: somepassword
  https.host: secure.sample.com
  https.port: 443
  https.username: jim
  https.password: wright62

Note: Some networks require that separate proxy servers are used for HTTP and HTTPS URLs. In such a case, you can set both the proxy.http and proxy.https objects.

Specifying Encryption Keys

Properties may be encrypted while at rest in the Git backend(s), either with symmetric or asymmetric keys, and then decrypted when provider and slice resources are reconciled. When encrypted properties are decrypted, they are written to a Secret resource instead of a ConfigMap resource. All other properties in Git that are not encrypted will still be written to a ConfigMap resource, as usual.

Encrypted values should be saved in Git with a {cipher} prefix. For example, if the value “Tanzu Tacos” were encrypted with a symmetric key of “secret”, then a property in application.yml in the Git repository might look like this:

cook:
  special: '{cipher}f0d2bbbe8621b471988a6fea3ac7213afaff8c692a4be444749e577163304a44'

Note that the single quotes are required when specifying the property in a YAML file so that the curly-braces aren’t misinterpreted.

To specify the key to be used for decryption, specify the encryption.key parameter in the credentials Secret. For example, using a symmetric key of “secret”, the credentials Secret might look like this:

apiVersion: v1
kind: Secret
metadata:
  name: habuma-creds
stringData:
  encryption.key: secret

If using an asymmetric key pair, if the value is encrypted using a public key, set the encryption.key value to the private key.

Defining a Configuration Slice

A configuration slice is a namespaced resource that is defined by a handful of parameters:

Parameter Function
provider The name of a ClusterConfigProvider resource the defines backends from which configuration will be accessed.
content A list of entries defining the subset of properties to pull from the backends in the configuration provider.
configMapName The name to give to the ConfigMap created. Defaults to the same name as the ConfigurationSlice.
secretName The name to give to the Secret created. Defaults to the same name as the ConfigurationSlice.
immutable If true, create an immutable ConfigMap and/or Secret, with a unique hash suffix on the name. Otherwise, create a mutable ConfigMap and/or Secret with no suffix attached to the name. Default: true
configMapStrategy If “tree”, then create a ConfigMap and/or Secret with one property per property found in the provider/slice combination. If “applicationProperties”, create a ConfigMap and/or Secret with a single property named “application.properties” whose value is a properties file structure. This is to enable applications that do not support configuration tree volume mounts, such as applications built with versions of Spring Boot prior to Spring Boot 2.4.

A configuration slice is defined in a YAML manifest with a kind of ConfigurationSlice. The simplest configuration slice definition specifies only the provider and content parameters. For example:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ConfigurationSlice
metadata:
  name: cook-config-slice
spec:
  provider: cook-config-provider
  content:
  - cook/production
  - cook/features/my-branch

To create a configuration slice, use kubectl apply like this:

$ kubectl apply -f my-config-slice.yaml

This will create the configuration slice and, after a few seconds, a ConfigMap resource containing properties obtained via the referenced configuration provider and for the entries listed under content.

In the given example, configuration will be pulled from one or more backends using the two paths listed under content. Content entries are made up of three components:

{APP NAME}/{PROFILE NAME}/{LABELS}
  • {APP NAME} — The name of an application for which the configuration is being retrieved. If “application”, then this is considered the default application and includes configuration shared across multiple applications. Any other value specifies a specific application (in the example given, “cook” is the application name) and will include properties for both the specified application as well as shared properties for the default application.
  • {PROFILE NAME} — The name of a profile for which properties may be retrieved. If “default” or “*”, then this includes properties that are shared across any all profiles. If any non-default value, then the slice will include properties for the specified profile as well as properties for the default profile.
  • {LABELS} — An optional comma-separated list of labels from which to retrieve properties. If not specified, then the default is to pull properties from a branch named “master”. If specified, then properties will be retrieved from all listed labels, but not from the “master” branch (unless it is included in the list).

Creating Immutable ConfigMap/Secret Resources

By default, any ConfigMap or Secret resource created by ACS will be immutable. That is, these resources will be created as immutable, meaning that they cannot be changed once created and may only be deleted. Moreover, they will be given a unique name with a suffix that is a hash of their contents.

For example, if ACS creates an immutable ConfigMap with the base name of “cook-configuration”, the ConfigMap will be created as immutable with a name like “cook-configuration-559fa7b62c9…” (where “-559fa7b62c9…” is a unique suffix hash). If the slice or provider change to result in a different set of properties, then a new ConfigMap will be created alongside the original with a different hash suffix.

If you would prefer that ACS create mutable ConfigMap and Secret resources, then set immutable to false when defining the ConfigurationSlice resource. For example:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ConfigurationSlice
metadata:
  name: cook-config-slice
spec:
  provider: cook-config-provider
  configMapName: cook-configuration
  content:
  - cook/production

This will result in a mutable ConfigMap whose name is simply “cook-configuration”. If the slice or provider change such that the properties in the ConfigMap will be updated, then the same ConfigMap will be updated to reflect the new values.

Specifying ConfigMap/Secret Names

By default, the ConfigMap and Secret resources created by ACS will be given a name that is the same as the ConfigurationSlice resource, plus a unique hash suffix if immutable is true.

For example, if immutable is true and the name of the ConfigurationSlice is “cook-config-slice”, then the created ConfigMap will be something like “cook-config-slice-559fa7b62c9…”, where the “-559fa7b62c9…” will be unique to the contents of the ConfigMap. If immutable is false, then the name of the ConfigMap will simply be “cook-config-slice”, the same as the name of the ConfigurationSlice.

The same naming convention applies to Secret resources, if created.

To customize the name of the produced ConfigMap, set the configMapName parameter. For example:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ConfigurationSlice
metadata:
  name: cook-config-slice
spec:
  provider: cook-config-provider
  configMapName: cook-configuration
  content:
  - cook/production

This will result in a ConfigMap whose base name is “cook-configuration”.

Likewise, you can set the base name for a Secret by specifying secretName:

apiVersion: "acs.tanzu.vmware.com/v1beta1"
kind: ConfigurationSlice
metadata:
  name: cook-config-slice
spec:
  provider: cook-config-provider
  configMapName: cook-configuration
  secretName: cook-secrets
  content:
  - cook/production

This will result in a Secret whose base name is “cook-secrets”.

Storing Configuration Properties

When using a Git configuration source, you can store properties in YAML or Java .properties files. Configuration properties can be applicable to all apps, specific to an app, or specific to an application profile.

Global Configuration

You can store configuration properties so that they are intended for consumption by all apps. In the configuration repository, a file named application.yml or application.properties contains configuration which are intended for all applications.

Using YAML

An example of a global application.yml file:

message: Hi there!

Using a Properties File:

An example of a global application.yml file:

message=Hi there!

Application-Specific Configuration

You can store configuration properties so that they are intended only for a specific app. In the configuration repository, a file named [APP-NAME].yml or [APP-NAME].properties, where [APP-NAME] is the name of an app, contains configuration which is intended for the APP-NAME app.

Using YAML

An example of an app-specific cook.yml file:

server:
  port: 80

cook:
  special: Fried Salamander

Using a Properties File

An example of an app-specific cook.properties file:

server.port=80

cook.special=Fried Salamander

Profile-Specific Configuration

You can store configuration properties so that they are intended only for apps which have activated a specific application profile. In the configuration repository, a file named [APP-NAME]-[PROFILE-NAME].yml or [APP-NAME]-[PROFILE-NAME].properties, where [APP-NAME] is the name of an app and [PROFILE-NAME] is the name of an application profile, contains configuration which will be available only to the APP-NAME app running with the [PROFILE-NAME] profile activated. Within a YAML file named [APP-NAME].yml, a document that begins by setting the spring.profiles property contains configuration which will be available only to the APP-NAME app running with the profile specified by the ConfigurationSlice in the content list.

Using YAML

An example of a profile-specific cook-dev.yml file:

server:
  port: 8080

cook:
  special: Birdfeather Tea

An example of a profile-specific YAML document within a cook.yml file:

---
spring:
  profiles: dev

server:
  port: 8080

cook:
  special: Birdfeather Tea

Using a Properties File

An example of a profile-specific cook-dev.properties file:

server.port=8080

cook.special=Birdfeather Tea