AssumeRoleWithCertificate
The MinIO AIStor Security Token Service (STS) AssumeRoleWithCertificate API endpoint generates temporary access credentials using a client X.509 (TLS) certificate.
This page documents the AIStor Server AssumeRoleWithCertificate endpoint.
For instructions on implementing STS using an S3-compatible SDK, defer to the documentation for that SDK.
Unlike OpenID Connect or AD/LDAP, certificate-based authentication does not depend on an external identity provider being continuously available. AIStor authenticates the request using only the client certificate, which can reduce operational complexity and improve availability.
Enable certificate-based authentication
The TLS STS API is disabled by default.
Enable it by setting the MINIO_IDENTITY_TLS_ENABLE environment variable to on and restarting the deployment.
Because authentication and authorization rely on the client certificate, all AssumeRoleWithCertificate requests must use TLS (HTTPS) and the client must present exactly one leaf client certificate.
AIStor verifies the client certificate against the same set of root certificate authorities it trusts for everything else, not against a certificate authority reserved for client identity. The policy name comes from the certificate itself, either the SPIFFE workload path or the subject common name.
Together, those two facts have one consequence.
Any CA in the deployment’s trust store can issue a certificate whose SPIFFE workload path or subject common name matches a policy name, including an administrative policy.
That trust store is not limited to the CAs/ directory.
It also holds the host’s system root certificates and the public certificates of the server’s own TLS key pairs.
Curating CAs/ therefore does not by itself create an allowlist for client identity.
Before you enable this API, confirm that every CA the deployment trusts is one you would allow to mint identities.
Configuration
The TLS STS API supports the following environment variables:
| Environment variable | Description |
|---|---|
MINIO_IDENTITY_TLS_ENABLE |
Set to on to enable X.509 TLS certificate single sign-on. Defaults to off. |
MINIO_IDENTITY_TLS_SKIP_VERIFY |
Set to on to trust client certificates without verifying that they were issued by a trusted Certificate Authority (CA). Defaults to off (verify).
Skipping verification allows any client to obtain temporary credentials with arbitrary policy permissions, including administrative permissions. Only set this to
on for debugging or testing.
|
MINIO_IDENTITY_TLS_SPIFFE_MULTI_DOMAIN |
Set to on to qualify the policy name derived from a SPIFFE SVID with its trust domain, so that identical workload paths in different trust domains map to different policies. Defaults to off.See SPIFFE SVID authentication for details. |
You can also configure these values using the standard configuration API with the identity_tls subsystem:
mc admin config set ALIAS identity_tls skip_verify="off"
Request endpoint
The AssumeRoleWithCertificate endpoint has the following form:
POST https://aistor.example.net?Action=AssumeRoleWithCertificate[&ARGS]
The following example uses all supported arguments.
Replace the aistor.example.net hostname with the appropriate URL for your AIStor Server, and provide the client certificate and private key with the request:
curl -X POST --key private.key --cert public.crt \
"https://aistor.example.net?Action=AssumeRoleWithCertificate&Version=2011-06-15&DurationSeconds=3600"
Request query parameters
This endpoint supports the following query parameters:
| Parameter | Type | Description |
|---|---|---|
Version |
string | Required Specify 2011-06-15. |
DurationSeconds |
integer | Optional Specify the number of seconds after which the temporary credentials expire. Defaults to 3600.- The minimum value is 900 or 15 minutes.- The maximum value is 31536000 or 365 days.The temporary credentials never outlive the client certificate. If the requested duration extends beyond the certificate’s expiration, AIStor reduces the credential lifetime to match the certificate. |
TokenRevokeType |
string | Optional A string to assign to the generated token that allows the token’s access to be revoked before expiration. A user may have a maximum of 100 unique token revocation types at any time. A token revocation type can be assigned to multiple tokens. |
Certificate-to-policy mapping
AIStor maps the client certificate to an S3 policy using the subject common name (CN) of the X.509 certificate.
A certificate with the subject CN = consoleAdmin is associated with the policy named consoleAdmin.
The certificate must meet the following requirements:
- The subject common name (CN) must not be empty and must match an existing policy name.
- The certificate must include the
TLS Web Client Authenticationextended key usage. AIStor rejects certificates that cannot be used for client authentication. - Unless
MINIO_IDENTITY_TLS_SKIP_VERIFYis set toon, the certificate must be issued by a CA that the AIStor server trusts.
The following self-signed certificate is issued for consoleAdmin, so AIStor associates it with the pre-defined consoleAdmin policy:
Certificate:
Data:
Version: 3 (0x2)
Signature Algorithm: ED25519
Issuer: CN = consoleAdmin
Validity
Not Before: Jul 19 15:08:44 2021 GMT
Not After : Aug 18 15:08:44 2021 GMT
Subject: CN = consoleAdmin
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
Group mapping is not possible with standard X.509 certificates.
Authentication flow
Certificate-based authentication proceeds in four steps:
- The client sends an HTTP
POSTrequest over a TLS connection to the AIStor TLS STS endpoint, presenting its client certificate. - AIStor verifies that the client certificate is valid.
- AIStor finds the policy whose name matches the certificate’s subject common name (CN).
- AIStor returns temporary S3 credentials associated with the matched policy.
SPIFFE SVID authentication
In addition to classic X.509 common name (CN) authentication, AIStor validates SPIFFE SVIDs presented as client certificates for AssumeRoleWithCertificate.
A SPIFFE SVID is an X.509 certificate that carries a SPIFFE ID (for example, spiffe://example.org/myservice) in a URI Subject Alternative Name (SAN).
When the leaf client certificate contains any URI SAN with the spiffe scheme, AIStor treats the certificate as a SPIFFE SVID and validates it accordingly:
- AIStor validates the certificate as a SPIFFE X.509 SVID using the SPIFFE reference library (
github.com/spiffe/go-spiffe/v2). The certificate must contain exactly one valid SPIFFE ID URI SAN. - If the SVID is invalid, AIStor rejects the request.
There is no fallback to the certificate’s subject common name (CN) for a certificate that presents a
spiffeURI. - The SPIFFE ID must include a workload path.
A SPIFFE ID with an empty path (for example,
spiffe://example.org/) is rejected because no policy name can be derived from it.
SVID validation runs in addition to the existing certificate checks.
Unless MINIO_IDENTITY_TLS_SKIP_VERIFY is set to on, the certificate must still be issued by a CA that AIStor trusts and must include the TLS Web Client Authentication extended key usage.
SPIFFE-to-policy mapping
AIStor derives the S3 policy name from the workload path of the SPIFFE ID:
- By default, AIStor uses only the path component of the SPIFFE ID, with the leading
/removed. The SPIFFE IDspiffe://example.org/myservicemaps to a policy namedmyservice. - When
MINIO_IDENTITY_TLS_SPIFFE_MULTI_DOMAINis set toon, AIStor qualifies the policy name with the trust domain in the form<trust-domain>/<path>. The SPIFFE IDspiffe://example.org/myservicemaps to a policy namedexample.org/myservice. Use this option when identical workload paths exist in different trust domains and must map to different policies.
The derived policy name must match an existing policy exactly. As with CN-based authentication, group mapping is not possible with SPIFFE SVIDs.
Scoping access by workload identity
AIStor selects the policy by name, as described above, so a policy named after each workload path must exist. Substitution does not change that. What it changes is the content of those policies: instead of writing a bespoke document per workload, you write one document that refers to the caller and reuse it unchanged for every workload.
AIStor exposes the workload path as the jwt:sub condition key, and substitutes it into resource paths and conditions when it evaluates a request.
To give every workload its own prefix in a shared bucket, use ${jwt:sub} in the resource:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": ["arn:aws:s3:::shared-bucket/${jwt:sub}/*"]
}
]
}
Create that policy once per workload path, using the same file every time:
mc admin policy create ALIAS billing/api ./workload-policy.json
mc admin policy create ALIAS billing/reports ./workload-policy.json
A certificate for spiffe://example.org/billing/api then reaches only shared-bucket/billing/api/*, and a certificate for spiffe://example.org/billing/reports reaches only its own prefix.
Because the text never varies, you can generate these policies from your workload registry, and no workload can be granted another’s prefix by an editing mistake.
To harden a policy against being reused by an identity it was not written for, match jwt:sub in a condition as well:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::telemetry/*"],
"Condition": {
"StringLike": { "jwt:sub": "ingest/*" }
}
}
]
}
The policy then grants nothing unless the caller’s workload path begins with ingest/, even if the policy is later attached to another identity.
Note the following behavior:
jwt:subholds the same value AIStor used to select the policy. WhenMINIO_IDENTITY_TLS_SPIFFE_MULTI_DOMAINis set toon, that value includes the trust domain, sospiffe://example.org/billing/apisubstitutes asexample.org/billing/apirather thanbilling/api. Write both resource paths and condition patterns to match the form you configured. With multi-domain qualification on, the resource pattern becomesarn:aws:s3:::shared-bucket/example.org/billing/api/*and the condition pattern becomes"jwt:sub": "example.org/ingest/*". A pattern written for the unqualified form denies the very workloads it is meant to allow.- Substitution uses the first value of a condition key.
jwt:subcarries a single value, so the result is unambiguous for workload identities. - AIStor substitutes only condition keys it recognizes.
If a key is unknown, or its value is empty, AIStor leaves the
${...}text in the pattern unchanged. The resulting pattern matches no object, so a missing identity denies access rather than widening it. - Bucket policies do not apply here. AIStor evaluates bucket policies only for anonymous requests, so an authenticated workload is governed by its own policy alone.
Without substitution, a client certificate selects a policy that an administrator wrote.
With ${jwt:sub} in a resource path, the workload path inside the certificate also selects the object prefix.
Combined with the trust store behavior described at the top of this page, any CA the deployment trusts can mint a certificate for any workload path, and therefore for any prefix the policy covers. Do not rely on prefix substitution alone to separate tenants unless you control every CA in the trust store.
Response elements
MinIO AIStor returns an AssumeRoleWithCertificateResult object, where the Credentials object contains the temporary credentials generated by AIStor:
AccessKeyId- The access key applications use for authentication.SecretAccessKey- The secret key applications use for authentication.Expiration- The ISO-8601 date-time after which the credentials expire.SessionToken- The session token applications use for authentication. Some SDKs may require this field when using temporary credentials.
The following example is similar to the response returned by the AIStor Server STS AssumeRoleWithCertificate endpoint:
<?xml version="1.0" encoding="UTF-8"?>
<AssumeRoleWithCertificateResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
<AssumeRoleWithCertificateResult>
<Credentials>
<AccessKeyId>YC12ZBHUVW588BQAE5BM</AccessKeyId>
<SecretAccessKey>Zgl9+zdE0pZ88+hLqtfh0ocLN+WQTJixHouCkZkW</SecretAccessKey>
<Expiration>2021-07-19T20:10:45Z</Expiration>
<SessionToken>eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9...</SessionToken>
</Credentials>
</AssumeRoleWithCertificateResult>
<ResponseMetadata>
<RequestId>169339CD8B3A6948</RequestId>
</ResponseMetadata>
</AssumeRoleWithCertificateResponse>
Considerations
Applications that use the S3 API directly work without issue. However, interactive users uploading content from a browser (for example, when a browser POSTs to a presigned URL the application generates) may see a prompt to provide a client certificate. The user must cancel that prompt to continue. There is no workaround for this behavior at this time.
Error elements
The XML error response for this API endpoint is similar to the AWS AssumeRoleWithWebIdentity response.