# Configure credentials

When deploying the stack for the first time, credentials are generated randomly.

While it could be "enough", there are issues with generated credentials:

* The credentials will conflict when uninstalling the stack and reinstalling it.
* Integration with secret managers is not possible.
* Breaks configuration-as-code principles, reducing predictability and traceability.

Per best practices, it is **recommended to use a secret manager** to store credentials.

## Parameters

Here's the location of the parameters you need to configure:

{% code title="yaml: values.override.yaml" %}

```yaml
global:
  oauth2:
    # OAuth client secrets
    clientSecrets:
      # Explicitely, random strings
      gatewayToucan: ''
      toucanAdminManagement: ''
      toucanEmbed: ''
      toucanImpersonateService: ''
      toucanImpersonateServiceEmbed: ''
      toucanInfraAdmin: ''
      toucanLaputaWebsocket: ''
      toucanMicroService: ''
      # OR a secret that contains the keys:
      # - curity-gateway-toucan-client-secret
      # - toucan-admin-management-client-secret
      # - toucan-embed-client-secret
      # - toucan-impersonate-service-client-secret
      # - toucan-impersonate-service-embed-client-secret
      # - toucan-infra-admin-client-secret
      # - toucan-laputa-websocket-client-secret
      # - toucan-micro-service-client-secret
      existingSecret: ''

  toucan:
    auth:
      adminAccount: admin@example.com

      password: ''
      # OR a secret that contains the key: toucan-admin-password
      existingSecret: ''

  postgresql:
    auth:
      postgresPassword: "" # super admin user password (username is 'postgres')
      username: "" # default user, owner of the default database
      password: "" # default user password
      database: "" # default database name
      # OR, a secret that contains the keys:
      existingSecret: ''
      secretKeys:
        userPasswordKey: password

  s3:
    ## @param global.s3.keys Dictionary of access keys.
    keys:
      dataexecution:
        name: 'dataexecution'
        ## @param global.s3.keys.expiration Expiration date of the key in RFC3339 format
        expiration: ''
        neverExpires: true

        id: 'GKbb1d479bf94cff5d3044047d' # Format: "GK" + 24 hex characters (openssl rand -hex 12)
        # If the secret is not provided, a random key will be generated.
        secret: '' # Format: 64 hex characters (openssl rand -hex 32)

        ## @param global.s3.keys.existingSecret Name of an existing secret to use for Garage keys.
        ## `global.s3.keys.secret` will be ignored and picked up from this secret.
        ## The value is evaluated as a template.
        existingSecret:
          name: ''
          key: 'dataexecution-secret-key'

      toucan:
        name: 'toucan'
        expiration: ''
        neverExpires: true
        id: 'GK633befbddc55fbdd8a7c64ef'
        secret: ''
        existingSecret:
          name: ''
          key: 'toucan-secret-key'

      toucan_ro:
        name: 'toucan_ro'
        expiration: ''
        neverExpires: true
        id: 'GKf4da50cffb2390de07d9e3b5'
        secret: ''
        existingSecret:
          name: ''
          key: 'toucan-ro-secret-key'

laputa:
  secrets:
    # Encrypt the database
    dbEncryptionSecret: ''
    # Used to sign the JWT
    jwtSecretKey: ''
    # OR a secret that contains the keys:
    # - laputa-db-encryption-secret
    # - laputa-jwt-secret-key
    existingSecret: ''

layout:
  initconfig:
    secrets:
      # Used to provision users. There is no need to use a secret manager
      # for this one.
      USER_PROVISIONING_SHARED_SECRET:
        name: ''
        key: layout-user-provisioning-shared-secret

curity:
  config:
    # Admin UI password
    adminPassword: ''
    # Encryption Key is used to encrypt the configuration.
    # To generate one: `openssl rand -hex 32`.
    encryptionKey: ''
    # OR a secret that contains the keys:
    # - curity-admin-password
    # - curity-encryption-key
    existingSecret: ''

    cluster:
      ## To generate one `docker run --rm -it curity.azurecr.io/curity/idsvr genclust -c unused -e <encryptionKey>`:
      ## keystore: "v:S.Tz..."
      ##
      keystore: ''
      ## OR:
      ## - A secret that contains the key: curity-config-cluster-keystore
      existingSecret: ''

vault:
  oauthapp:
    # A Vault token scoped to oauthapp. A random string.
    token: ''
    # OR a secret that contains the key: vault-token
    existingSecret: ''

mongodb:
  auth:
    # Root credentials. Unused by toucan.
    rootUser: admin
    rootPassword: ''

    # App credentials. Owner of any database inside mongodb.
    user: app
    password: ''
    readonlyUser: app_readonly
    readonlyPassword: ''

    # OR a secret that contains the keys:
    # - mongodb-root-password
    # - mongodb-app-password
    # - mongodb-app-readonly-password
    existingSecret: ''

spicedb:
  config:
    auth:
      # A random string
      presharedKey: ''
      # OR a secret that contains the key: spicedb-preshared-key
      existingSecret: ''

garage:
  secrets:
    rpc: '' # Hexadecimal string
    admin: '' # Hexadecimal string

    # OR a secret that contains the keys:
    # - garage-rpc-secret
    # - garage-admin-secret
    existingSecret: ''

laputa-redis:
  auth:
    password: ''
    # OR a secret that contains the key: redis-password
    existingSecret: ''
    existingSecretPasswordKey: redis-password

    ## @param existingSecret Name of an existing secret to use for Garage secrets.
    ## `garage.secrets.rpc` will be ignored and picked up from this secret.
    ## The value is evaluated as a template.
    ## It must contain the keys `garage-rpc-secret` and `garage-admin-secret`.
    existingSecret: ''

```

{% endcode %}

## Generating a secret quickly

Here's an all-in-one secret, containing all the credentials:

{% code title="yaml: /work/toucan-secret.local.yaml.tpl" overflow="wrap" %}

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: toucan-secret
  namespace: 'toucan'
type: Opaque
stringData:
  # The toucan Admin password. This is the most important one as it is the one used
  # to login to the Toucan Admin UI.
  toucan-admin-password: '{{ random.Alpha 32 }}'

  # Laputa's secrets
  laputa-db-encryption-secret: '{{ random.Alpha 32 }}'
  laputa-jwt-secret-key: '{{ random.Alpha 32 }}'

  # Curity admin password. This is also important if you plan to manage the
  # identity provider.
  curity-admin-password: '{{ random.Alpha 32 }}'
  curity-encryption-key: ''
  curity-cluster-keystore: ''

  # OAuth2 Secrets
  curity-gateway-toucan-client-secret: '{{ random.Alpha 32 }}'
  curity-toucan-admin-management-client-secret: '{{ random.Alpha 32 }}'
  curity-toucan-embed-client-secret: '{{ random.Alpha 32 }}'
  curity-toucan-impersonate-service-client-secret: '{{ random.Alpha 32 }}'
  curity-toucan-impersonate-service-embed-client-secret: '{{ random.Alpha 32 }}'
  curity-toucan-infra-admin-client-secret: '{{ random.Alpha 32 }}'
  curity-toucan-laputa-websocket-client-secret: '{{ random.Alpha 32 }}'
  curity-toucan-micro-service-client-secret: '{{ random.Alpha 32 }}'

  # SpiceDB credentials
  # NOTE: SpiceDB is also protected by mTLS.
  spicedb-preshared-key: '{{ random.Alpha 32 }}'

  # Vault shared token
  vault-token: '{{ random.Alpha 32 }}'

  # MongoDB credentials
  mongodb-root-password: '{{ random.Alpha 32 }}'
  mongodb-app-password: '{{ random.Alpha 32 }}'
  mongodb-app-readonly-password: '{{ random.Alpha 32 }}'

  # Redis credentials
  redis-password: '{{ random.Alpha 32 }}'

  # PostgreSQL credentials
  postgresql-postgres-password: '{{ random.Alpha 32 }}'
  postgresql-password: '{{ random.Alpha 32 }}'
  postgresql-replication-password: '{{ random.Alpha 32 }}'

  # Layout service shared secret
  layout-user-provisioning-shared-secret: '{{ random.Alpha 32 }}'

  # Garage
  dataexecution-secret-key: ''
  toucan-secret-key: ''
  toucan-ro-secret-key: ''
  garage-rpc-secret: ''
  garage-admin-secret: ''
```

{% endcode %}

In which, you can generate with [gomplate](https://github.com/hairyhenderson/gomplate):

{% code title="shell" overflow="wrap" %}

```shell
gomplate -f /work/toucan-secret.local.yaml.tpl > /work/toucan-secret.local.yaml
```

{% endcode %}

Replace the value of `curity-encryption-key` with the result of the command:

{% code title="shell" overflow="wrap" %}

```shell
openssl rand -hex 32
```

{% endcode %}

Do the same for `dataexecution-secret-key`, `toucan-secret-key`, `toucan-ro-secret-key`, `garage-rpc-secret` and `garage-admin-secret`.

Replace the value of `curity-cluster-keystore` with the result of the command:

{% code title="shell" overflow="wrap" %}

```shell
docker run --rm -it curity.azurecr.io/curity/idsvr genclust -c unused -e <encryptionKey> | grep keystore | sed -E 's/.*<keystore>(.*)<\/keystore>.*/\1/'
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs-v3.toucantoco.com/self-hosted-toucan/configuration/credentials.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
