Client Credentials
The Client Credentials service allows to expose APIs to perform OAuth2 compliant client credential flows with third-party providers. This means that authorized service accounts can obtain an access token to access protected resources, without the need to involve the user.
In this section, you will learn how to configure the client-credentials
service step by step.
Create the client collection
This service uses a crud-service collection to handle clients.
Create a CRUD collection in the MongoDB CRUD section of the Console with the name clients
(you can choose also another name if already taken in your project), download these fields, and import them into the Console (find out how to import fields here).
We suggest that you create a unique index for the clientId
field (which must not be duplicated).
Environment variables
This service is configurable with the following environment variables:
- USERID_HEADER_KEY (default to
miauserid
): name of the header carrying the identifier of the calling user; - ADDITIONAL_HEADERS_TO_PROXY (default to
miauserid,miausergroups,miauserproperties
): list of comma separated header keys which will be proxied to any external http service the Client Credentials might call (for the moment, is just the CRUD Service). By default, the Client Credentials services proxies the following headers:Request-Id
,X-Request-Id
,X-Forwarded-For
,X-Forwarded-Proto
,X-Forwarded-Host
; - LOG_LEVEL (default to
info
): level of the log. It could be trace, debug, info, warn, error, fatal; - HTTP_PORT (default to
3000
): port where the web server is exposed; - SERVICE_PREFIX: path prefix for all the specified endpoints (different from the status routes);
- DELAY_SHUTDOWN_SECONDS (default to
10
seconds): seconds to wait before starting the graceful shutdown. This delay is required in k8s to await for the dns rotation; - CRUD_CLIENT_BASE_URL (required): base url to the crud collection containing the client information. Example:
http://crud-service/clients
whereclients
is the internal endpoint exposed for theclients
collection created in the previous step; - CLIENT_ID_HASH_SALT (required): static hash salt used to save the client id. For example, can be a random string of 256 characters;
- CLIENT_SECRET_HASH_COST (default to
10
): the cost to generate the hash of the client secret (using bcrypt); - CREDENTIALS_MONGODB_URL (required): the mongo url pointing to the db which will handle the credentials information;
- CREDENTIALS_COLLECTION_NAME (default to
credentials
): collection to save the credentials information; - MONGODB_CREDENTIALS_DATABASE_NAME: the mongo db name which will include the
credentials
collection. If not set, it is taken from the MongoDB URL configured inCREDENTIALS_MONGODB_URL
env var; - PRIVATE_RSA_KEY_FILE_PATH (required): path to mount the private RSA key. Click here to see how to create it;
- PRIVATE_KEY_PASSWORD: password to decrypt the RSA key, if it is encrypted with a password. If it is empty, RSA key is treated as a non protected RSA key;
- PRIVATE_RSA_KEY_ID (required): id of the private key. It will be added to the kid of the generated JWT. This is a random string;
- MIA_JWT_ISSUER (required): string containing the issuer to fill the JWT claims. During the login flow, it is added as iss;
- MIA_JWT_EXPIRES_IN (required): expiration time for the generated JWT, in seconds;
- REQUIRED_AUDIENCE_IN_TOKEN_REQUEST (default to
false
): if audience is required in token request; - ACCEPTED_AUDIENCES: comma-separated list of audiences accepted by the service, if included in JWT
aud
claim; - OPENID_CONFIG_PATH: string representing the path to the file contaning the OpenId Connect Configuration.
- REDIS_HOSTS (required): redis host with port (default Redis port is 6379);
- REDIS_USERNAME (optional): the username to authenticate to Redis;
- REDIS_PASSWORD (optional): the password to authenticate to Redis;
- REDIS_MODE: defines the redis mode (
normal
orsentinel
) (default:normal
); - REDIS_TLS (optional): if
true
, enable the TLS connection to Redis. Default isfalse
; - REDIS_TLS_CACERT (optional): the path to the CA of the Redis server, if it's not public (this is effective only if
REDIS_TLS
is set totrue
); - REDIS_MASTER_NAME: defines the redis master name (required when using
sentinel
mode); - CLOCK_SKEW_SECONDS: defines the skew seconds that will be used into the
/token
request to validate the iat and notBefore claims of the client_assertion and reduce client and server clocks misalignment
RSA Key Management
An RSA key is a type of asymmetric cryptographic key used in public-key cryptography. In an RSA key pair, there are two keys: a public key and a private key.
The public key can be freely distributed and is used to encrypt messages that can only be decrypted with the private key. The private key, on the other hand, is kept secret and is used to decrypt the messages that have been encrypted with the public key.
Creation
This service accepts a private RSA key to sign the generated JWT (JSON Web Token). Refer to the related section for an explanation on how to generate it.
Deploy key in the Kubernetes cluster
Configure the service volume from Console
In the Console, on the client-credentials
service, add a new configuration of type secret named client-credential-private-key
and set the mount path at /configs
.
Once this is done, set the environment variable PRIVATE_RSA_KEY_FILE_PATH
value to /configs/private.key
to configure it correctly.
Deploy with mlp
If you use mlp, the Mia-Platform deploy cli, to release custom secrets add these lines to the mlp.yaml
file in your project:
secrets:
- name: "client-credential-private-key"
when: "always"
data:
- from: "literal"
key: "private.key"
value: "{{PRIVATE_KEY}}"
If you use GitLab as CI tool, set the environment variable PRIVATE_KEY
with the value of the private key (copy the value using pbcopy < private.key
).
Configure the service volume manually
You should set the key as volume from secret in the client-credentials
service.
This is an example to add a secret to a volume:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-pod
image: my-image
env:
- name: PRIVATE_RSA_KEY_FILE_PATH
value: /configs/private.key
volumeMounts:
- name: client-credential-private-key
mountPath: "/configs"
readOnly: true
volumes:
- name: client-credential-private-key
secret:
secretName: client-credentials-private-key
With this configuration the created pod will be mounted with the secret generated from file private.key
; the mount path inside the container will be /configs/private.key
. Make sure your configuration is correct by checking that this is the value you have set for PRIVATE_RSA_KEY_FILE_PATH
environment variable.
Deploy directly in namespace
You should create the key as secret in kubernetes, using:
kubectl -n my-namespace create secret generic my-secret --from-file="~/private.key"
OpenID Configuration
To expose the OpenId discovery endpoint correctly you should provide the configuration using a config map. This file must contain the exact JSON that will then be sent as response.
apiVersion: v1
data:
config.json: '{ "issuer": "https://www.valid.url", ... }'
kind: ConfigMap
metadata:
name: client-credentials
Now you have to load the config map inside a volume and mount that volume, as follows:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-pod
image: my-image
env:
- name: OPENID_CONFIG_PATH
value: /openid/config.json
volumeMounts:
- name: openid-config-volume
mountPath: "/openid"
readOnly: true
volumes:
- name: openid-config-volume
configMap:
name: openid-config
Note: the custom configuration MUST contain at least every required field.
Required fields:
- issuer
- token_endpoint
- jwks_uri
- response_types_supported
- subject_types_supported
- id_token_signing_alg_values_supported
Reference: OpenId Connect Discovery.