#################################### Configuring LTD Keeper on Kubernetes #################################### In a production deployment, Keeper is configured entirely through environment variables (see :file:`config.py` in the Keeper repo). The pod template files set these environment variables through `Kubernetes Secrets `_ and `ConfigMaps `_. See the ``env`` section in :file:`kubernetes/keeper-pod.yaml`, for example. The Keeper Git repository includes four configuration templates: 1. :file:`kubernetes/keeper-config.template.yaml` creates a ConfigMap resource named ``keeper-config`` and is used for non-secure Keeper Flask web app configurations. 2. :file:`kubernetes/keeper-secrets.template.yaml` creates a Secret resource named ``keeper-secrets`` and is used to configure the Keeper Flask web app. 3. :file:`kubernetes/ssl-proxy-secrets.template.yaml` creates a Secret resource named ``ssl-proxy-secret`` and is used to supply TLS certs to the Nginx proxy service. 4. :file:`kubernetes/cloudsql-secrets` creates a Secret resource named ``cloudsql-secrets`` containing credentials for the Google Cloud SQL instance. Using the secrets ================= The best way to maintain configurations is copy the configuration templates and modify them. Since the staging and production environments might have different secrets, we recommend maintaining both ``-prod`` and ``-staging`` files: .. code-block:: bash cp kubernetes/keeper-config.template.yaml kubernetes/keeper-config-prod.yaml cp kubernetes/keeper-config.template.yaml kubernetes/keeper-config-staging.yaml cp kubernetes/keeper-secrets.template.yaml kubernetes/keeper-secrets-prod.yaml cp kubernetes/keeper-secrets.template.yaml kubernetes/keeper-secrets-staging.yaml cp kubernetes/ssl-proxy-secrets.template.yaml kubernetes/ssl-proxy-secrets-prod.yaml cp kubernetes/ssl-proxy-secrets.template.yaml kubernetes/ssl-proxy-secrets-staging.yaml cp kubernetes/cloudsql-secrets.template.yaml kubernetes/cloudsql-secrets-prod.yaml cp kubernetes/cloudsql-secrets.template.yaml kubernetes/cloudsql-secrets-staging.yaml These configuration files are automatically ignored by Git. Setting and deploying secrets ============================= Secrets are set as key-value pairs in the ``data`` field of secrets YAML files. For example: .. code-block:: yaml apiVersion: v1 kind: Secret metadata: name: keeper-secrets type: Opaque data: secret-key: aGVsbG8td29ybGQ= # ... A Pod template file can reference this secret named ``secret-key`` in this ``keeper-secrets`` resource as: .. code-block:: yaml apiVersion: v1 kind: Pod # ... spec: containers: - name: uwsgi # ... env: - name: LTD_KEEPER_SECRET_KEY valueFrom: secretKeyRef: name: keeper-secrets key: secret-key # ... Now the environment variable ``LTD_KEEPER_SECRET_KEY`` in the ``uwsgi`` container has the value from ``secret-key``. .. _gke-encoding-secrets: Encoding secrets ---------------- The values of secrets in the Secrets YAML files must be base64 encoded. A convenient command for encoding a string (and copying it to the clipboard on OS X) is .. code-block:: bash echo -n "secret-value" | base64 | pbcopy To encode a file: .. code-block:: bash base64 -i secret.key | pbcopy Two recommendations for working with secrets files: 1. Do not work with YAML files directly in the Keeper Git repository; copy them out of the repo first into a working directory. 2. In the edited ``*-secrets.yaml`` file it can be useful to added the un-encoded value as a comment. .. _gke-deploying-secrets: Deploying secrets ----------------- If the secrets file is named :file:`secrets.yaml`, it can be deployed with ``kubectl``: .. code-block:: bash kubectl create -f secrets.yaml You can review deployed secrets with: .. code-block:: bash kubectl get secrets And remove it: .. code-block:: bash kubectl delete secret SECRETS_NAME Note that containers, and other Kubernetes resources, only get secrets when they are first deployed. You need to re-deploy the Pod to update environment variables in a container. keeper-config reference ======================= The ``keeper-config`` resource (:file:`kubernetes/keeper-config.template.yaml`) provides non-secure configurations for the Flask app. ``server-name`` → ``LTD_KEEPER_URL`` The externally-facing domain name of the Keeper API server (for example, ``keeper.lsst.codes``). For a Kubernetes deployment this is the domain name attached to the external IP of the Ingress resource. Use ``keeper-staging.lsst.codes`` for staging deployments. ``profile`` → ``LTD_KEEPER_PROFILE`` Configuration profile for the Flask app. This should be ``'production'`` for any Kubernetes deployment, even a staging deployment. ``url-scheme`` → ``LTD_KEEPER_URL_SCHEME`` Configuration profile for the Flask app. URL scheme for the Flask App. Should be ``'https'`` since the Kubernetes deployment uses a TLS-terminating ingress proxy. ``dasher-url`` → ``LTD_DASHER_URL`` Cluster URL of the LTD Dasher app. This is determined by the Dasher app's service, and defaults to ``'http://dasher:3031 Configuration profile for the Flask app. URL scheme for the Flask App. Should be ``'https'`` since the Kubernetes deployment uses a TLS-terminating ingress proxy. keeper-secrets reference ======================== The ``keeper-secrets`` resource (:file:`kubernetes/keeper-secrets.template.yaml`) provides secure configurations for the Flask app. ``secret-key`` → ``LTD_KEEPER_SECRET_KEY`` The secret key for authentication. ``aws-id`` → ``LTD_KEEPER_AWS_ID`` Amazon Web Services key ID. This key must have access to AWS Route 53 and S3 for the documentation domains and storage bucket, respectively, used by LSST the Docs. ``aws-secret`` → ``LTD_KEEPER_AWS_SECRET`` Amazon Web Services secret corresponding to ``LTD_KEEPER_AWS_ID``. ``fastly-id`` → ``LTD_KEEPER_FASTLY_ID`` Fastly service ID. ``fastly-key`` → ``LTD_KEEPER_FASTLY_KEY`` Fastly API key. ``default-user`` → ``LTD_KEEPER_BOOTSTRAP_USER`` Username of the initial user for bootstrapping a Keeper DB. This bootstrap user is granted full API permissions. ``default-password`` → ``LTD_KEEPER_BOOTSTRAP_PASSWORD`` Password for the bootstrap user. ``db-url`` → ``LTD_KEEPER_DB_URL`` URL of Keeper's SQL database. For a Cloud SQL instance, this URL has the form: .. code-block:: text mysql+pymysql://root:@/keeper?unix_socket=/cloudsql/:: Replace ``PASSWORD`` with the database password (see :doc:`gke-cloudsql`), along with ``PROJECT`` and ``REGION`` with the Cloud SQL instance details (see :doc:`gke-setup` and doc:`gke-cloudsql``). Remember that this is a URI, so any unusual characters (particularly in the password) must be escaped/quoted. Python's `urllib.parse.quote `__ can help prepare a URL. See the `SQLAlchemy Database Urls docs `_ for more information. Finally, note that we recommend the ``pymysql`` 'dialect' MySQL. The PyMySQL package is automatically installed with LTD Keeper in its docker container. cloudsql-secrets reference ========================== This section describes :file:`kubernetes/cloudsql-secrets.yaml`, which provides the ``cloudsql-secrets`` resource. ``file.json`` This is a base64-encoded JSON service account credential file. A Google Cloud Platform Service Account was created earlier in :doc:`gke-cloudsql`. .. code-block:: bash base64 -i credentials.json | pbcopy Further documentation for the Cloud SQL Proxy can be found in the `github.com/GoogleCloudPlatform/cloudsql-proxy `__ repository's README. ssl-proxy-secret reference ========================== This section describes the :file:`kubernetes/ssl-proxy-secrets.template.yaml`, which provides ``ssl-proxy-secret`` to the ssl-proxy pods. These secrets includes the SSL certificate, SSL private key, and a DHE parameter. ``proxycert`` The SSL certificate (combined with the intermediate). Encode this value with: .. code-block:: bash base64 -i example_org.crt | pbcopy ``proxykey`` The SSL private key. .. code-block:: bash base64 -i example_org.key | pbcopy ``dhparam`` The DHE parameter. .. code-block:: bash openssl dhparam -out dhparam.pem 2048 base64 -i dhparam.pem