diff --git a/docs/FAQ.md b/docs/FAQ.md index 146348b..e86ecf5 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -1,12 +1,12 @@ --- title: "The secrets-store-integration module: FAQ" -description: Hashicorp vault example configuration. Example of secret autorotation implementation. +description: Hashicorp Vault configuration examples. Example of secret autorotation implementation. --- -## How to set up the Hashicorp vault as a secret store for use with the secrets-store-integration module: +## How to set up the Hashicorp Vault as a secret store to use with the secrets-store-integration module: -First of all, we need a root or similiar token and the vault address. -Root token can be obtained during new secrets store initialization. +First of all, you'll need a root or similiar token and the vault address. +You can get such a root token while initializing a new secrets store. ```bash @@ -14,17 +14,17 @@ export VAULT_TOKEN=xxxxxxxxxxx export VAULT_ADDR=https://secretstoreexample.com ``` -In this guide we provide two ways to obtain needed result: -- usage of the console version of the Hashicorp Vault (Installation guide: https://developer.hashicorp.com/vault/docs/install) -- usage of the cURL equivalent command to make a direct requests to the secrets store API +This guide will cover two ways to do this: +- using the console version of HashiCorp Vault (see the installation guide: https://developer.hashicorp.com/vault/docs/install); +- using curl to make direct requests to the secrets store API. -Enable and create Key-Value storage: +Enable and create the Key-Value store: ```bash vault secrets enable -path=secret -version=2 kv ``` -or curl equivalent: +The same command as a curl HTTP request: ```bash curl \ @@ -34,13 +34,13 @@ curl \ ${VAULT_ADDR}/v1/sys/mounts/secret ``` -Set a secret with a database password: +Set the database password as the secret value: ```bash vault kv put secret/database-for-python-app password="db-secret-password" ``` -or curl equivalent: +The curl equivalent of the above command: ```bash curl \ @@ -50,13 +50,13 @@ curl \ ${VAULT_ADDR}/v1/secret/data/database-for-python-app ``` -Double-check that it is written: +Double-check that the password has been saved successfully: ```bash vault kv get secret/database-for-python-app ``` -or curl equivalent: +The curl equivalent of the above command: ```bash curl \ @@ -70,7 +70,7 @@ Allow authentication and authorization in the vault with Kubernetes API by defin vault auth enable -path=main-kube kubernetes ``` -or curl equivalent: +The curl equivalent of the above command: ```bash curl \ @@ -80,13 +80,13 @@ curl \ ${VAULT_ADDR}/v1/sys/auth/main-kube ``` -If we have more than one cluster, we need to allow authentication and authorization in the vault with Kubernetes API for the second cluster, defining the second authentication path: +If you have more than one cluster, set the authentication path (authPath) and enable authentication and authorization in Vault using the Kubernetes API of the second cluster: ```bash vault auth enable -path=secondary-kube kubernetes ``` -or curl equivalent: +The curl equivalent of the above command: ```bash curl \ @@ -96,14 +96,14 @@ curl \ ${VAULT_ADDR}/v1/sys/auth/secondary-kube ``` -Set up Kubernetes API address for each auth point (in that case, it is k8s API server service): +Set the Kubernetes API address for each cluster (in this case, it is the K8s's API server service): ```bash vault write auth/main-kube/config \ kubernetes_host="https://api.kube.my-deckhouse.com" ``` -or curl equivalent: +The curl equivalent of the above command: ```bash curl \ @@ -118,7 +118,7 @@ vault write auth/secondary-kube/config \ kubernetes_host="https://10.11.12.10:443" ``` -or curl equivalent: +The curl equivalent of the above command: ```bash curl \ @@ -128,7 +128,7 @@ curl \ ${VAULT_ADDR}/v1/auth/secondary-kube/config ``` -Create an internal-app policy in the vault: +Create a policy in Vault named `backend` that allows reading secrets: ```bash vault policy write backend - < This is the most secure option, but it requires an application to be modified. -3. The storage is accessed by the layering application, and your application gets access to the secrets from the environment variables. -*Recommendation:* If you can't read from files, you can use this option, but it is NOT secure, because the secret data is stored in Kubernetes (and etcd, so it can potentially be read on any node in the cluster). +2. An intermediate application retrieves secrets from the vault, and your application retrieves secrets from files created in the container. + + > Use this option if you cannot modify the application for some reason. It is less secure because the secrets are stored in files in the container. However, it is easier to implement. + +3. An intermediate application retrieves secrets from the vault, and your application accesses the secrets as the environment variables. + + > If reading from files is unavailable, you can opt for this alternative. Keep in mind, however, that it is NOT secure, because the secret data is stored in Kubernetes (and etcd, so it can potentially be read on any node in the cluster). - + - - - + + + - - - + + + - - + + - - - - + + + + - - + + - - - - + + + +
How secrets are being delivered?How secrets are being delivered Resources consumptionHow your application gets the data?Where the secret is stored in the Kubernetes?СтатусHow your application gets the dataWhere the secret is stored in the KubernetesStatus
AppDoesn't changeDirectly from secrets storeIs not storedNo changesDirectly from the secrets storeNot stored Implemented
CSI Interface Two pods per node (daemonset)
  • From disk volume (as a file)
  • From environment variable
Is not stored
  • From the disk volume (as a file)
  • From the environment variable
Not stored Implemented
Entrypoint injectionOne app for whole cluster (deployment)Secrets are delivered as environment variables during application startIs not storedIn the process of implementationOne app for the whole cluster (deployment)Secrets are delivered as environment variables at application startupNot storedimplementation is in progress
Kubernetes SecretsOne app for whole cluster (deployment)
  • From disk volume (as a file)
  • From environment variable
One app for the whole cluster (deployment)
  • From the disk volume (as a file)
  • From the environment variable
Stored as a Kubernetes Secret Planned for implementation and release
Vault-agent InjectorOne agent per one pod (sidecar)From disk volume (as a file)Is not stored*No plans to implementOne agent per pod (sidecar)From the disk volume (as a file)Not stored*No implementation plans
-*No plans to implement. There are no advantages over the CSI interface. +*No implementation plans. There are no advantages over the CSI interface. -### Option #1: Get the secrets from the app itself +### Option #1: Getting the secrets using the app itself -> *Status:* The most secure option. Recommended for use if there is a possibility of application modification. +> *Status:* the most secure option. Recommended if you can access the application and modify it. -The application accesses Stronghold API and requests the necessary secret via HTTPS protocol using authorization token (token from SA). +The application accesses the Stronghold API and retrieves the secret over HTTPS using the SA authorization token. #### Pros: -- The secret received by the application is not stored anywhere except in the application itself, there is no danger that it will be compromised during transmission +- The secret received by the application is not stored anywhere other than the application itself. There is no danger that it will be compromised during the transmission. #### Cons: -- Requires customization of the application to be able to work with Stronghold -- Requires reimplementation of secret access in each application, and if library is updated, rebuilds all applications -- Application must support TLS and certificate validation -- No caching, when restarting the application you need to re-request the secret directly from the repository +- The application will need to be modified for it to work with Stronghold. +- You would have to re-implement secret access in each application, and if the library is updated, you would have to rebuild all the applications. +- The application must support TLS and certificate validation. +- No caching is available. When the application restarts, it will have to re-request the secret straight from the storage. -### Option #2: Deliver secrets through files +### Option #2: Delivering secrets using files #### CSI interface -> *Status:* Secure option. Recommended for use if there is no way to modify applications. +> *Status:* secure option. Recommended if you cannot make changes to the application. -When creating pods requesting CSI volumes, the CSI secret vault driver sends a request to Vault CSI. Vault CSI then uses the specified SecretProviderClass and ServiceAccount feed to retrieve secrets from the vault and mount them in the pod volume. +When creating pods that request CSI volumes, the CSI secret vault driver sends a request to the Vault CSI. The Vault CSI then uses the specified SecretProviderClass and ServiceAccount of the pod to retrieve the secrets from the vault and mount them in the pod volume. -#### Environment Variable Injection: +#### Environment variable injection: -In a situation where there is no way to modify the application code, then you can implement secure secret injection as an environment variable for the application. To do this, read all the files CSI has mounted in the container and define environment variables with names corresponding to the file names and values corresponding to the contents of the files. After that, run the original application. - -Example in bash: +If there is no way to change the application code, you can implement secure secret injection as an environment variable that the application can use. To do so, read all the files mounted by the CSI into the container and define the environment variables so that their names correspond to the file names and values correspond to the file contents. After that, run the application. Refer to the Bash example below. ```bash bash -c "for file in $(ls /mnt/secrets); do export $file=$(cat /mnt/secrets/$file); done ; exec my_original_file_to_startup" @@ -110,40 +111,42 @@ bash -c "for file in $(ls /mnt/secrets); do export $file=$(cat /mnt/secrets/$fi #### Pros: -- Only two containers with predictable resources on each node to serve the secret delivery system to applications. +- Only two containers, whose resource requirements are known in advance, are required on each node to deliver secrets to applications. - Creating SecretsStore/SecretProviderClass resources reduces the amount of repetitive code compared to other vault agent implementations. -- It is possible to create a copy of the secret from the vault as a kubernetes secret if needed. -- The secret is retrieved from the vault by the CSI driver during the container creation phase. This means that starting pods will be blocked until the secrets are read from the repository and written to the volume of the container. +- If necessary, you can create a Kubernetes secret that is a copy of the secret retrieved from the vault. +- The secret is retrieved from the vault by the CSI driver at the container creation stage. This means that pods will be started only after the secrets are read from the vault and written to the container volume. ### Option №3: Entrypoint injection -#### Environment variables delivery into the container through entrypoint injection +#### Delivering environment variables into the container through entrypoint injection -> *Статус:* Secure option. In the process of implementation +> *Status:* secure option. This option is currently being developed. -Environment variables are being delivered into the container during the application start and are located only in memory. During the first stage of implementation delivery will be made with the entrypoint injection. Afterwards, delivery mechanism will be integrated into containerd. +Environment variables are propagated into the container at application startup. They are stored in RAM only. At first, variables will be delivered via the entrypoint injection into the container. In the future, we plan to integrate the secrets delivery mechanism into containerd. -### Option #4: Delivering secrets through Kubernetes mechanisms +### Option #4: Delivering secrets using Kubernetes mechanisms -> *Status:* Not a safe option, not recommended for use. No support is available, but it is planned for the future. +> *Status:* not secure; not recommended for use. No support is available. It may be implemented in the future.. -This integration method implements a Kubernetes secrets operator with a set of CRDs responsible for synchronizing secrets from Vault to Kubernetes secrets. +This integration method relies on the Kubernetes secrets operator with a set of CRDs for synchronizing secrets from Vault to the Kubernetes secrets. -#### Minuses: +#### Pros: -- The secret is located both in the secret store and the Kubernetes secret. It is accessible through the Kubernetes API, as well as in Etcd, which means it can potentially be read on any node in the cluster or extracted from an Etcd backup. The secret data will be always stored as Kubernetes secret. +- This is the traditional way of passing a secret to an application via environment variables - all you have to do is to hook up the Kubernetes secret. -#### Pros: +#### Cons: -- The classic way to transfer a secret to an application through environment variables is to connect the Kubernetes secret. +- The secret is stored in both the secret store and the Kubernetes secret (which can be accessed via the Kubernetes API). The secret is also stored in etcd and can potentially be read on any cluster node or retrieved from an etcd backup. No option to avoid storing data in Kubernetes secrets is available. ### For reference: vault-agent injector -> *Status:* Has no pros compared to the CSI mechanism. No support and implementation is available or planned. +> *Status:* no pros compared to the CSI mechanism. No support/implementation is available or in plans. + +When a pod is created, a mutation is run that adds a vault-agent container. The vault-agent retrieves the secrets from the secret store and puts them in a shared volume on a disk that can be accessed by the application. + +#### Cons: -When a pod is created, a mutation occurs that adds a vault-agent container. The vault-agent accesses the secret store, retrieves the secret, and places it into a shared volume on a disk that can be accessed by the application. +- Each pod requires running a sidecar container, which consumes resources. Suppose there are 50 applications running in a cluster, each having 3 to 15 replicas. While the resource requirements of each sidecar are low, the numbers get noticeable when multiplied by the total number of containers: 50mcpu + 100Mi per sidecar means dozens of CPU cores and dozens of gigabytes of RAM. -#### Minuses: -- Each pod needs a sidecar, which consumes resources in one way or another. Let's imagine a cluster with 50 applications, each with 3 to 15 replicas. The sidecar with an agent needs to allocate CPU and memory resources. Although small, it is very noticeable. 50mcpu + 100Mi for one sidecar and in total for all applications will consume tens of cores and tens of gigabytes of RAM. -- Since we are monitoring metrics from each container, with this approach we will get x2 metrics just by container. +- Since metrics are collected from each container, this approach will produce twice as many container metrics. diff --git a/docs/README_RU.md b/docs/README_RU.md index a2300b4..3d3d3c6 100644 --- a/docs/README_RU.md +++ b/docs/README_RU.md @@ -6,8 +6,8 @@ description: "Модуль secrets-store-integration реализует инте Модуль secrets-store-integration реализует доставку секретов для приложения в Kubernetes-кластерах путем подключения секретов, ключей и сертификатов, хранящихся во внешних хранилищах секретов. -Секреты монтируются в модули в виде тома с использованием реализации драйвера CSI. -Хранилища секретов должны быть совместимы с API-интерфейсом Hashicorp Vault. +Секреты монтируются в поды в виде тома с использованием реализации драйвера CSI. +Хранилища секретов должны быть совместимы с API-интерфейсом HashiCorp Vault. ## Доставка секретов в приложения @@ -15,15 +15,15 @@ description: "Модуль secrets-store-integration реализует инте 1. Пользовательское приложение само обращается в хранилище. - Рекомендация: Это наиболее безопасный вариант, но требует модификации приложений. + > Это наиболее безопасный вариант, но требует модификации приложений. -1. В хранилище обращается приложение-прослойку, а ваше приложение получает доступ к секретам из файлов, созданных в контейнере. +1. В хранилище обращается приложение-прослойка, а ваше приложение получает доступ к секретам из файлов, созданных в контейнере. - Рекомендация: Если нет возможности модифицировать приложение, используйте этот вариант. Он проще в реализации, но менее безопасный, так как секретные данные хранятся в файлах в контейнере. + > Если нет возможности модифицировать приложение, используйте этот вариант. Он проще в реализации, но менее безопасный, так как секретные данные хранятся в файлах в контейнере. 1. В хранилище обращается приложение-прослойка, и пользовательское приложение получает доступ к секретам из переменных среды. - Рекомендация: Если нет возможности читать из файлов, можно использовать этот вариант, но он не безопасен. При таком подходе секретные данные хранятся в Kubernetes (а так же в etcd) и потенциально могут быть прочитаны на любом узле кластера. + > Если нет возможности читать из файлов, можно использовать этот вариант, но он небезопасен. При таком подходе секретные данные хранятся в Kubernetes (а так же в etcd) и потенциально могут быть прочитаны на любом узле кластера. @@ -78,12 +78,12 @@ description: "Модуль secrets-store-integration реализует инте ### Вариант №1: Получение секретов самим приложением -> *Статус:* Наиболее безопасный вариант. Рекомендован к использованию, если есть возможность модификации приложений. +> *Статус:* наиболее безопасный вариант. Рекомендован к использованию, если есть возможность модификации приложений. Приложение обращается к API Stronghold и запрашивает необходимый секрет по HTTPS-протоколу с использованием токена авторизации (токен из SA). Плюсы: -- Секрет, полученный приложением, нигде не хранится, кроме как в самом приложении, нет опасности что он будет скомпрометирован в процессе передачи +- Секрет, полученный приложением, нигде не хранится, кроме как в самом приложении, нет опасности что он будет скомпрометирован в процессе передачи. Минусы: @@ -96,9 +96,9 @@ description: "Модуль secrets-store-integration реализует инте #### Механизм CSI -> *Статус:* Безопасный вариант. Рекомендован к использованию, если отсутствует возможность модификация приложений. +> *Статус:* безопасный вариант. Рекомендован к использованию, если отсутствует возможность модификация приложений. -При создании подов запрашивающих тома CSI, драйвер хранилища секретов CSI отправляет запрос к Vault CSI. Затем, Vault CSI использует указанный SecretProviderClass и ServiceAccount пода для получения секретов из хранилища и монтирования их в том пода. +При создании подов, запрашивающих тома CSI, драйвер хранилища секретов CSI отправляет запрос к Vault CSI. Затем Vault CSI использует указанный SecretProviderClass и ServiceAccount пода для получения секретов из хранилища и монтирования их в том пода. #### Инъекция переменных окружений: @@ -109,7 +109,7 @@ description: "Модуль secrets-store-integration реализует инте - определить переменные окружения с именами, соответствующими именам файлов, и значениями, соответствующим содержимому файлов. - запустить оригинальное приложение. -Пример на bash: +Пример на Bash: ```bash bash -c "for file in $(ls /mnt/secrets); do export $file=$(cat /mnt/secrets/$file); done ; exec my_original_file_to_startup" @@ -126,19 +126,19 @@ bash -c "for file in $(ls /mnt/secrets); do export $file=$(cat /mnt/secrets/$fi #### Доставка переменных окружения через инъекцию entrypoint в контейнер -> *Статус:* Безопасный вариант. В процессе реализации. +> *Статус:* безопасный вариант. В процессе реализации. -Переменные доставляются из хранилища в момент запуска приложения и находятся только в памяти. В момент первого этапа реализации метода, переменные будут доставляться через entrypoint, инжектированный в контейнер. В дальнейшем планируется интеграция функционала доставки секретов в containerd. +Переменные доставляются из хранилища в момент запуска приложения и находятся только в памяти. В момент первого этапа реализации метода переменные будут доставляться через entrypoint, проброшенный в контейнер. В дальнейшем планируется интеграция функционала доставки секретов в containerd. ### Вариант №4: Доставка секретов через механизмы Kubernetes -> *Статус:* Небезопасный вариант, не рекомендован к использованию. Поддержка отсутствует, но планируется в будущем. +> *Статус:* небезопасный вариант, не рекомендован к использованию. Поддержка отсутствует, но планируется в будущем. Этот метод интеграции, который реализует оператор секретов Kubernetes с набором CRD, отвечающих за синхронизацию секретов из Vault в секреты Kubernetes. Минусы: -- Секрет находится и в хранилище секретов, и в секрете Kubernetes (доступном через API Kubernetes). Секрет также хранится в etcd, и потенциально может быть считан на любом узле кластера или извлечён из резервной копии etcd. Нет возможности не хранить данные в секретах Kubernetes. +- Секрет находится и в хранилище секретов, и в секрете Kubernetes (доступном через API Kubernetes). Секрет также хранится в etcd и потенциально может быть считан на любом узле кластера или извлечён из резервной копии etcd. Нет возможности не хранить данные в секретах Kubernetes. Плюсы: @@ -146,7 +146,7 @@ bash -c "for file in $(ls /mnt/secrets); do export $file=$(cat /mnt/secrets/$fi ### Справочно: Инжектор vault-agent -> *Статус:* Не имеет плюсов в сравнении с механизмом CSI. Поддержка отсутствует и не планируется, поскольку этот вариант не имеет преимуществ перед использованием механизма CSI. +> *Статус:* не имеет плюсов в сравнении с механизмом CSI. Поддержка отсутствует и не планируется, поскольку этот вариант не имеет преимуществ перед использованием механизма CSI. При создании пода происходит мутация, которая добавляет контейнер с vault-agent. Агент обращается к хранилищу секретов, извлекает их, и помещает в общий том на диске, к которому может обратиться приложение. @@ -154,5 +154,5 @@ bash -c "for file in $(ls /mnt/secrets); do export $file=$(cat /mnt/secrets/$fi - Для каждого пода нужен sidecar-контейнер, который так или иначе потребляет ресурсы. - Например, возьмем кластер в котором 50 приложений, и каждое приложение имеет от 3 до 15 реплик. Так как для каждого sidecar-контейнера с агентом нужно выделить ресурсы CPU и памяти, то даже при незначительных ресурсах для sidecar-контейнера в размере 0.05 CPU и 100MiB памяти, на все приложения в сумме получитятся десятки ядер CPU и десятки ГБ памяти. + Например, возьмем кластер в котором 50 приложений, и каждое приложение имеет от 3 до 15 реплик. Так как для каждого sidecar-контейнера с агентом нужно выделить ресурсы CPU и памяти, то даже при незначительных ресурсах для sidecar-контейнера в размере 0.05 CPU и 100 MiB памяти, на все приложения в сумме получаются десятки ядер CPU и десятки ГБ памяти. - Так как сбор метрик осуществляется с каждого контейнера, то с таким подходом мы получим в два раза больше метрик только по контейнерам. \ No newline at end of file diff --git a/docs/USAGE.md b/docs/USAGE.md index 4e94dbb..dfc133a 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -3,11 +3,11 @@ title: "The secrets-store-integration module: usage" description: Usage of the secrets-store-integration Deckhouse module. --- -## How to set up the module for work with Deckhouse Stronghold +## Configuring the module to work with Deckhouse Stronghold -To automatically set up the secrets-store-integration module for work with [Deckhouse Stronghold](../../stronghold/) you need to [turn on](../../stronghold/stable/usage.html#how-to-enable-the-module) the Stronghold module previously. +[Enable](../../stronghold/stable/usage.html#how-to-enable-the-module) the Stronghold module beforehand to automatically configure the secrets-store-integration module to work with [Deckhouse Stronghold](../../stronghold/). -After that just apply the ModuleConfig: +Next, apply the ModuleConfig: ```yaml apiVersion: deckhouse.io/v1alpha1 @@ -19,15 +19,15 @@ spec: version: 1 ``` -The [connectionConfiguration](../../secrets-store-integration/stable/configuration.html#parameters-connectionconfiguration) paramater is optional, it is set to `DiscoverLocalStronghold` value by default. +The [connectionConfiguration](../../secrets-store-integration/stable/configuration.html#parameters-connectionconfiguration) paramater is optional and set to `DiscoverLocalStronghold` value by default. -## How to set up the module for work with external secrets store +## Configuring the module to work with the external secret store -To operate the module, a preconfigured secrets store compatible with HashiCorp Vault is required. The store must have an authentication path configured in advance. An example of configuring the secrets store is provided in the FAQ. +The module requires a pre-configured secret vault compatible with HashiCorp Vault. An authentication path must be preconfigured in the vault. An example of how to configure the secret vault is provided in the FAQ. -To ensure that each API request is encrypted, sent, and responded to by the correct recipient, a valid public Certificate Authority (CA) certificate used by the secrets store is required. You need to use such a public CA certificate in PEM format as the caCert variable in the module configuration. +To ensure that each API request is encrypted, sent to, and replied by the correct recipient, a valid public Certificate Authority certificate used by the secret store is required. A `caCert` variable in the module configuration must refer to such a CA certificate in PEM format. -The following is an example module configuration for using a Vault-compatible secrets store deployed at "secretstoreexample.com" on the default TLS port, 443 TLS. Please note that you'll need to replace the variable values in the configuration with the actual values corresponding to your environment. +The following is an example module configuration for using a Vault-compliant secret store running at "secretstoreexample.com" on a regular port (443 TLS). Note that you will need to replace the variable values in the configuration with the values that match your environment. ```yaml apiVersion: deckhouse.io/v1alpha1 @@ -50,92 +50,249 @@ spec: -----END CERTIFICATE----- ``` -To verify that every API request is encrypted, sent, and answered by the exact host, we must embed the caCert of the used Vault-compatible secrets storage in PEM format in the ModuleConfig. +To ensure that each API request is encrypted, sent and responded to by the exact host that sent it, insert the PEM-formatted caCert for the Vault-compatible secret store into ModuleConfig. -**It is strongly recommended to set the caCert variable, if not, the module will use the system ca-certificates.** +**It is strongly recommended to set the `caCert` variable. Otherwise, the module will use system ca-certificates.** -To deliver secrets to the application, use the “SecretStoreImport” CustomResource. +## Setting up the test environment -## Mounting the vault’s secret as a file to a container: +Before moving on to the instructions for secret injection given in the examples below, -Let’s create namespace +1. Create a kv2 type secret in Stronghold in `secret/myapp` and copy `DB_USER` and `DB_PASS` there. +2. Create a policy in Stronghold that allows reading secrets from `secret/myapp`. +3. Create a `myapp` role in Stronghold for the `myapp` service account in the `my-namespace` namespace and bind the policy you created earlier to it. +4. Create a `my-namespace` namespace in the cluster. +5. Create a `myapp` service account in the created namespace. + +Example commands to set up the environment: ```bash -kubectl create namespace my-namespace1 +stronghold secrets enable -path=secret -version=2 kv + +stronghold kv put secret/myapp DB_USER="username" DB_PASS="secret-password" + +stronghold policy write myapp - <