Secrets management

Warning

this feature is EXPERIMENTAL and might not work as expected.
If you encounter any bugs, please fill an issue, it will help us a lot :)

Secrets are generally confidential values that should not appear in plain text in the application. There are several products that help you store, retrieve, and rotate these secrets securely. Otoroshi offers a mechanism to set up references to these secrets in its entities to benefits from the perks of your existing secrets management infrastructure. This feature only work with the new proxy engine.

A secret can be anything you want like an apikey secret, a certificate private key or password, a jwt verifier signing key, a password to a proxy, a value for a header, etc.

Enable secrets management in otoroshi

By default secrets management is disbaled. You can enable it by setting otoroshi.vaults.enabled or ${OTOROSHI_VAULTS_ENABLED} to true.

Global configuration

Secrets management can be only configured using otoroshi static configuration file (also using jvm args mechanism). The configuration is located at otoroshi.vaults where you can find the global configuration of the secrets management system and the configurations for each enabled secrets management backends. Basically it looks like

vaults {
  enabled = false
  enabled = ${?OTOROSHI_VAULTS_ENABLED}
  secrets-ttl = 300000 # 5 minutes
  secrets-ttl = ${?OTOROSHI_VAULTS_SECRETS_TTL}
  cached-secrets = 10000
  cached-secrets = ${?OTOROSHI_VAULTS_CACHED_SECRETS}
  read-timeout = 10000 # 10 seconds
  read-timeout = ${?OTOROSHI_VAULTS_READ_TIMEOUT}
  # if enabled, only leader nodes fetches the secrets.
  # entities with secret values filled are then sent to workers when they poll the cluster state.
  # only works if `otoroshi.cluster.autoUpdateState=true`
  leader-fetch-only = false
  leader-fetch-only = ${?OTOROSHI_VAULTS_LEADER_FETCH_ONLY}
  env {
    type = "env"
    prefix = ${?OTOROSHI_VAULTS_ENV_PREFIX}
  }
}

you can see here the global configuration and a default backend configured that can retrieve secrets from environment variables.

The configuration keys can be used for

  • secrets-ttl: the amount of milliseconds before the secret value is read again from backend
  • cached-secrets: the number of secrets that will be cached on an otoroshi instance
  • read-timeout: the timeout (in milliseconds) to read a secret from a backend

Entities with secrets management

the entities that support secrets management are the following

  • routes
  • services
  • service_descriptors
  • apikeys
  • certificates
  • jwt_verifiers
  • authentication_modules
  • targets
  • backends
  • tcp_services
  • data_exporters

Define a reference to a secret

in the previously listed entities, you can define, almost everywhere, references to a secret using the following syntax:

${vault://name_of_the_vault/secret/of/the/path}

let say I define a new apikey with the following value as secret ${vault://my_env/apikey_secret} with the following secrets management configuration

vaults {
  enabled = true
  secrets-ttl = 300000
  cached-secrets = 10000
  read-ttl = 10000
  my_env {
    type = "env"
  }
}

if the machine running otoroshi has an environment variable named APIKEY_SECRET with the value verysecret, then you will be able to can an api with the defined apikey client_id and a client_secret value of verysecret

curl 'http://my-awesome-api.oto.tools:8080/api/stuff' -u awesome_apikey:verysecret

Possible backends

Otoroshi comes with the support of several secrets management backends.

Environment variables

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "env"
    prefix = "the_prefix_added_to_the_name_of_the_env_variable"
  }
}

Local

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "local"
    root = "the_root_path/in_otoroshi/environment"
  }
}

value of this vault can be configured in the danger zone > Global metadata > Otoroshi environment.

Infisical

a backend for the awesome open source project Infisical. It support both E2EE and non E2EE secrets.

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "infisical"
    baseUrl = "https://app.infisical.com" # optional, the base url of your infisical server, fallbacks to https://app.infisical.com
    serviceToken = "st.xxxx.yyyy.zzzz" # the service token for your projet
    e2ee = true # are you secrets end to end encrypted
    defaultSecretType = "shared" # optional, fallbacks to shared
    defaultWorkspaceId = "xxxxxx" # optional, value can be passed in the secret address
    defaultEnvironment = "dev" # optional, value can be passed in the secret address
  }
}

you should define your references like ${vault://infisical_vault/my_secret_path?workspaceId=xxx&environment=dev&type=shared}. workspaceId, environment and type are optional if filled in global config.

You can also pass a json_pointer=/foo/bar to handle the value like a json document a select a value inside it.

Hashicorp Vault

a backend for Hashicorp Vault. Right now we only support KV engines.

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "hashicorp-vault"
    url = "http://127.0.0.1:8200"
    mount = "kv" # the name of the secret store in vault
    kv = "v2" # the version of the kv store (v1 or v2)
    token = "root" # the token that can access to your secrets
  }
}

you should define your references like ${vault://hashicorp_vault/secret/path/key_name}.

Azure Key Vault

a backend for Azure Key Vault. Right now we only support secrets and not keys and certificates.

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "azure"
    url = "https://keyvaultname.vault.azure.net"
    api-version = "7.2" # the api version of the vault
    tenant = "xxxx-xxx-xxx" # your azure tenant id, optional
    client_id = "xxxxx" # your azure client_id
    client_secret = "xxxxx" # your azure client_secret
    # token = "xxx" possible if you have a long lived existing token. will take over tenant / client_id / client_secret
  }
}

you should define your references like ${vault://azure_vault/secret_name/secret_version}. secret_version is mandatory

If you want to use certificates and keys objects from the azure key vault, you will have to specify an option in the reference named azure_secret_kind with possible value certificate, privkey, pubkey like the following :

${vault://azure_vault/myprivatekey/secret_version?azure_secret_kind=privkey}

AWS Secrets Manager

a backend for AWS Secrets Manager

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "aws"
    access-key = "key"
    access-key-secret = "secret"
    region = "eu-west-3" # the aws region of your secrets management
  }
}

you should define your references like ${vault://aws_vault/secret_name/secret_version}. secret_version is optional

Google Cloud Secrets Manager

a backend for Google Cloud Secrets Manager

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "gcloud"
    url = "https://secretmanager.googleapis.com"
    apikey = "secret"
  }
}

you should define your references like ${vault://gcloud_vault/projects/foo/secrets/bar/versions/the_version}. the_version can be latest

AlibabaCloud Cloud Secrets Manager

a backend for AlibabaCloud Secrets Manager

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "alibaba-cloud"
    url = "https://kms.eu-central-1.aliyuncs.com"
    access-key-id = "access-key"
    access-key-secret = "secret"
  }
}

you should define your references like ${vault://alibaba_vault/secret_name}

Kubernetes Secrets

a backend for Kubernetes secrets

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "kubernetes"
    # see the configuration of the kubernetes plugin, 
    # by default if the pod if well configured, 
    # you don't have to setup anything
  }
}

you should define your references like ${vault://k8s_vault/namespace/secret_name/key_name}. key_name is optional. if present, otoroshi will try to lookup key_name in the secrets stringData, if not defined the secrets data will be base64 decoded and used.

Izanami config.

a backend for Izanami config.

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "izanami"
    url = "http://127.0.0.1:8200"
    client-id = "client"
    client-secret = "secret"
  }
}

you should define your references like ${vault://izanami_vault/the:secret:id/key_name}. key_name is optional if the secret value is not a json object

Spring Cloud Config

a backend for Spring Cloud Config.

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "spring-cloud"
    url = "http://127.0.0.1:8000"
    root = "myapp/prod"
    headers {
      authorization = "Basic xxxx"
    }
  }
}

you should define your references like ${vault://spring_vault/the/path/of/the/value} where /the/path/of/the/value is the path of the value.

Http backend

a backend for that uses the result of an http endpoint

the configuration of this backend should be like

vaults {
  ...
  name_of_the_vault {
    type = "http"
    url = "http://127.0.0.1:8000/endpoint/for/config"
    headers {
      authorization = "Basic xxxx"
    }
  }
}

you should define your references like ${vault://http_vault/the/path/of/the/value} where /the/path/of/the/value is the path of the value.