Let’s take an the cf-secrets.yml file from cf-boshworkspace, and see if we can convert it from a spiff based template to a spruce based template.
The original file is pretty big, so for simpliticy’s sake, lets strip it down to just this:
meta:
admin_secret: (( merge || c1oudc0wc1oudc0w ))
secret: (( merge || defaults.secret ))
secrets:
cc_bulk_api_password: (( merge || meta.secret ))
cc_staging_upload_password: (( merge || meta.secret ))
cc_db_encryption_key: (( merge || meta.secret ))
properties:
cc:
staging_upload_user: staging
bulk_api_password: (( meta.secrets.cc_bulk_api_password ))
staging_upload_password: (( meta.secrets.cc_staging_upload_password ))
db_encryption_key: (( meta.secrets.cc_db_encryption_key ))
uaa:
scim:
users:
- (( concat "admin|" meta.admin_secret "|scim.write,scim.read,openid,cloud_controller.admin,clients.read,clients.write,doppler.firehose" ))
defaults:
secret: c1oudc0w
The gist of this template is defining a default shared secret and admin password for CloudFoundry, allowing you to override it in later templates.
Since spruce
doesn’t need any special syntax to allow for overrides, we can probably get away with the defaults
and meta
sections. However, it would be useful to have a single place to store the shared secret, for easier referencing. Let’s have a start with this:
params:
admin_secret: c1oudc0wc1oudc0w
default_secret: c1oudc0w
properties:
cc:
staging_upload_user: staging
bulk_api_password: (( grab params.default_secret ))
staging_upload_password: (( grab params.default_secret ))
db_encryption_key: (( grab params.default_secret ))
uaa:
scim:
users:
- (( concat "admin|" params.admin_secret "|scim.write,scim.read,openid,cloud_controller.admin,clients.read,clients.write,doppler.firehose" ))
This is functionally equivalent to what we started with, but what if we wanted to force users to provide secrets, so they don’t go accidentally using a default password in an important deployment? Let’s look at the param
capability in spruce
:
params:
admin_secret: (( param "You need to specify an admin password for CF" ))
default_secret: (( param "You need to specify a shared-secret for this service, or provide params.default_secret" ))
properties:
cc:
staging_upload_user: staging
bulk_api_password: (( grab params.default_secret ))
staging_upload_password: (( grab params.default_secret ))
db_encryption_key: (( grab params.default_secret ))
uaa:
scim:
users:
- (( concat "admin|" params.admin_secret "|scim.write,scim.read,openid,cloud_controller.admin,clients.read,clients.write,doppler.firehose" ))
Now, users have a few options:
- Override
params.default_secret
directly, and all the keys referencing it will have the same secret:
params:
admin_secret: mySecretPassword
default_secret: superSecretSharedSecret
- Override each key that would reference
params.default_secret
to get unique secrets for each service:
params:
admin_secret: mySecretPassword
properties:
cc:
bulk_api_password: bulk_api_super_secret
staging_upload_password: staging_upload_password_OooOOoo
db_encryption_key: evenMoreSecretEncryptionKey
- Give a default secret to most services, while providing a unique secret to a handful:
params:
admin_secret: mySecretPassword
default_secret: supersecretsharedsecret
properties:
cc:
db_encryption_key: evenMoreSecretEncryptionKey
Lets choose the last option, and merge them together:
spruce merge condensed-cf-secrets.yml overrides.yml
params:
admin_secret: mySecretPassword
default_secret: supersecretsharedsecret
properties:
cc:
bulk_api_password: supersecretsharedsecret
db_encryption_key: evenMoreSecretEncryptionKey
staging_upload_password: supersecretsharedsecret
staging_upload_user: staging
uaa:
scim:
users:
- admin|mySecretPassword|scim.write,scim.read,openid,cloud_controller.admin,clients.read,clients.write,doppler.firehose
This output still has the params
key, which isn’t used by anything other than the templates. It would be nice if we could get rid of that to clean things up.
spruce merge --prune params condensed-cf-secrets.yml overrides.yml
properties:
cc:
bulk_api_password: supersecretsharedsecret
db_encryption_key: evenMoreSecretEncryptionKey
staging_upload_password: supersecretsharedsecret
staging_upload_user: staging
uaa:
scim:
users:
- admin|mySecretPassword|scim.write,scim.read,openid,cloud_controller.admin,clients.read,clients.write,doppler.firehose
Hmm. That did the trick, but can we be sure that the pruning didn’t remove our param safeguards? Let’s try again, but leave out the values of the params keys
spruce merge --prune params condensed-cf-secrets.yml overrides.yml
2 error(s) detected:
- $.properties.cc.bulk_api_password: You need to specify a shared-secret for this service, or provide params.default_secret
- $.properties.cc.staging_upload_password: You need to specify a shared-secret for this service, or provide params.default_secret
As hoped, the errors showed up. We now have a working spruce template!