Files
minio/docs/sts/ldap.md
T
Feng Ruohang c46b16ec62 chore: cut over to pgsty/silo and main
The transitional references land in one commit, because they are only correct
together: the repository is pgsty/silo, its default branch is main, and nothing
in the tree should point a user at the old names.

Changed:

- Workflow branch filters. go.yml and vulncheck.yml gated on `branches: master`
  for both push and pull_request, so renaming the default branch would have
  taken automatic CI offline with no error and no signal - the workflows would
  simply never trigger again. They now name main.
- Release target. goreleaser's `release.github.name` becomes silo, which is
  what actually decides where a tagged build publishes. sign-release-rpms.sh's
  GH_REPO default follows.
- The OCI `image.source` label, the Helm chart `sources` entry, the security
  advisory link in the issue-template config, and the go.mod comment citing the
  LDAP TLS fix.
- 115 occurrences across README, README_ZH, SECURITY, CONTRIBUTING and 30 docs
  pages, including 72 links that also carried the master branch in their path.
  Those matter most: GitHub redirects clone, fetch, push and web URLs after a
  rename, but raw.githubusercontent.com does not, and neither follows a branch
  rename - every one of those links would 404 twice over.
- Three error strings in cmd/erasure-sets.go, cmd/storage-errors.go and
  internal/config/errors.go that print an issue URL to operators. These are Go
  string literals inside rebrand-guard's brand allowlist, so the baseline is
  regenerated. The regeneration removes exactly those three entries and adds
  none; all twelve other protected sets, including the 9014 exported symbols,
  are byte-identical.
- The transitional-naming disclaimers in README, README_ZH, SECURITY and
  CONTRIBUTING are dropped, since they no longer describe anything.

Deliberately unchanged, all three because they exist to reject or freeze the old
name rather than to point at it:

- buildscripts/minio-upgrade.sh pins pgsty/minio@sha256:b6bfe72... - the frozen
  pre-rebrand image is the control group for the MinIO-to-Silo upgrade test.
- helm-migration-guard rejects any rendered container still pulling pgsty/minio.
- verify-rebrand.sh rejects the same in the delivery surfaces.

Also unchanged: docs/config/README.md links to pgsty/mc/blob/master, and that
repository's default branch really is still master. It moves when mc does.

verify-rebrand.sh gains three assertions so this cannot silently regress: no
source reference may name pgsty/minio outside the three allowlisted guards, no
link may target pgsty/silo's master branch, and go.yml and vulncheck.yml must
filter on main. Both new rejections were negative-tested - reintroducing a
master branch filter and adding a pgsty/minio URL each fail the gate with the
specific message.

This commit assumes the rename actually happens. Until the GitHub branch and
repository renames are executed, the links it introduces do not resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 09:28:06 +08:00

24 KiB

AssumeRoleWithLDAPIdentity

Introduction

Silo provides a custom STS API that allows integration with LDAP based corporate environments including Microsoft Active Directory. The Silo server uses a separate LDAP service account to lookup user information. The login flow for a user is as follows:

  • User provides their AD/LDAP username and password to the STS API.
  • Silo looks up the user's information (specifically the user's Distinguished Name) in the LDAP server.
  • On finding the user's info, Silo verifies the login credentials with the AD/LDAP server.
  • Silo optionally queries the AD/LDAP server for a list of groups that the user is a member of.
  • Silo then checks if there are any policies explicitly associated with the user or their groups.
  • On finding at least one associated policy, Silo generates temporary credentials for the user storing the list of groups in a cryptographically secure session token. The temporary access key, secret key and session token are returned to the user.
  • The user can now use these credentials to make requests to the Silo server.

The administrator will associate IAM access policies with each group and if required with the user too. The Silo server then evaluates applicable policies on a user (these are the policies associated with the groups along with the policy on the user if any) to check if the request should be allowed or denied.

To ensure that changes in the LDAP directory are reflected in object storage access changes, Silo performs an Automatic LDAP sync. Silo periodically queries the LDAP service to:

  • find accounts (user DNs) that have been removed; any active STS credentials or Silo service accounts belonging to these users are purged.

  • find accounts whose group memberships have changed; access policies available to a credential are updated to reflect the change, i.e. they will lose any privileges associated with a group they are removed from, and gain any privileges associated with a group they are added to.

Please note that when AD/LDAP is configured, Silo will not support long term users defined internally. Only AD/LDAP users (and the root user) are allowed. In addition to this, the server will not support operations on users or groups using mc admin user or mc admin group commands except mc admin user info and mc admin group info to list set policies for users and groups. This is because users and groups are defined externally in AD/LDAP.

Configuring AD/LDAP on Silo

LDAP STS configuration can be performed via Silo's standard configuration API (i.e. using mc admin config set/get commands) or equivalently via environment variables. For brevity we refer to environment variables here.

LDAP is configured via the following environment variables:

$ mc admin config set mysilo identity_ldap --env
KEY:
identity_ldap  enable LDAP SSO support

ARGS:
MINIO_IDENTITY_LDAP_SERVER_ADDR*            (address)   AD/LDAP server address e.g. "myldap.com" or "myldapserver.com:636"
MINIO_IDENTITY_LDAP_SRV_RECORD_NAME         (string)    DNS SRV record name for LDAP service, if given, must be one of "ldap", "ldaps" or "on"
MINIO_IDENTITY_LDAP_LOOKUP_BIND_DN          (string)    DN for LDAP read-only service account used to perform DN and group lookups
MINIO_IDENTITY_LDAP_LOOKUP_BIND_PASSWORD    (string)    Password for LDAP read-only service account used to perform DN and group lookups
MINIO_IDENTITY_LDAP_USER_DN_SEARCH_BASE_DN  (list)      ";" separated list of user search base DNs e.g. "dc=myldapserver,dc=com"
MINIO_IDENTITY_LDAP_USER_DN_SEARCH_FILTER   (string)    Search filter to lookup user DN
MINIO_IDENTITY_LDAP_USER_DN_ATTRIBUTES      (list)      "," separated list of user DN attributes e.g. "uid,cn,mail,sshPublicKey"
MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER     (string)    search filter for groups e.g. "(&(objectclass=groupOfNames)(memberUid=%s))"
MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN    (list)      ";" separated list of group search base DNs e.g. "dc=myldapserver,dc=com"
MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY         (on|off)    trust server TLS without verification (default: 'off')
MINIO_IDENTITY_LDAP_SERVER_INSECURE         (on|off)    allow plain text connection to AD/LDAP server (default: 'off')
MINIO_IDENTITY_LDAP_SERVER_STARTTLS         (on|off)    use StartTLS connection to AD/LDAP server (default: 'off')
MINIO_IDENTITY_LDAP_STS_TRUSTED_PROXIES     (list)      comma/semicolon/whitespace-separated list of trusted proxy IPs or CIDRs whose forwarded client IP headers may be used for LDAP STS rate limiting
MINIO_IDENTITY_LDAP_COMMENT                 (sentence)  optionally add a comment to this setting

LDAP server connectivity

The variables relevant to configuring connectivity to the LDAP service are:

MINIO_IDENTITY_LDAP_SERVER_ADDR*             (address)   AD/LDAP server address e.g. "myldap.com" or "myldapserver.com:1686"
MINIO_IDENTITY_LDAP_SRV_RECORD_NAME          (string)    DNS SRV record name for LDAP service, if given, must be one of ldap, ldaps or on
MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY         (on|off)    trust server TLS without verification, defaults to "off" (verify)
MINIO_IDENTITY_LDAP_SERVER_INSECURE         (on|off)    allow plain text connection to AD/LDAP server, defaults to "off"
MINIO_IDENTITY_LDAP_SERVER_STARTTLS         (on|off)    use StartTLS connection to AD/LDAP server, defaults to "off"

The server address variable is required. TLS is assumed to be on by default. The port in the server address is optional and defaults to 636 if not provided.

Silo sends LDAP credentials to the LDAP server for validation. So we strongly recommend to use Silo with AD/LDAP server over TLS or StartTLS only. Using plain-text connection between Silo and LDAP server means credentials can be compromised by anyone listening to network traffic.

If a self-signed certificate is being used, the certificate can be added to Silo's certificates directory, so it can be trusted by the server.

DNS SRV Records

Many Active Directory and other LDAP services are setup with DNS SRV Records for high-availability of the directory service. To use this to find LDAP servers to connect to, an LDAP client makes a DNS SRV record request to the DNS service on a domain that looks like _service._proto.example.com. For LDAP the proto value is always tcp, and service is usually ldap or ldaps.

To enable Silo to use the SRV records, specify the srv_record_name config parameter (or equivalently the MINIO_IDENTITY_LDAP_SRV_RECORD_NAME environment variable). This parameter can be set to ldap or ldaps and Silo will substitute it into the service value. For example, when server_addr=myldapserver.com and srv_record_name=ldap, Silo will lookup the SRV record for _ldap._tcp.myldapserver.com and pick an appropriate target for LDAP requests.

If the DNS SRV record is at an entirely different place, say _ldapsrv._tcpish.myldapserver.com, then set srv_record_name to the special value on and set server_addr=_ldapsrv._tcpish.myldapserver.com.

When using this feature, do not specify a port in the server_addr as the port is picked up automatically from the SRV record.

With the default (empty) value for srv_record_name, Silo will not perform any SRV record request.

The value of srv_record_name does not affect any TLS settings - they must be configured with their own parameters.

LDAP STS rate limiting

LDAP STS rate limiting is enforced before each LDAP bind. Requests are tracked by source IP. A login attempt is throttled when that bucket is exhausted. Rate limiting is deliberately not keyed by username: a username-keyed bucket is shared across all sources, so an attacker could drain a known account's bucket with bad-password attempts and lock the legitimate user out. The per-source bucket caps the attempt rate from any single source, while the uniform auth-failure response is what conceals whether a username exists. This combination does not stop attackers who spread requests across many source IPs (botnets, IPv6 address rotation) or the residual bind-timing side channel; those are accepted limitations of an in-memory, per-source control.

By default, the source IP used for this key is the socket peer address. This is the safe default because Silo does not trust X-Forwarded-For, X-Real-IP, or Forwarded headers for this security-sensitive rate-limit key unless you opt in explicitly.

Each login attempt reserves capacity for the duration of the LDAP bind. Successful logins and LDAP infrastructure failures refund that reservation. Only real authentication failures permanently consume tokens. Concurrent bursts above the burst capacity can still receive 429 responses even if those in-flight requests later succeed.

Behavior Value
Bucket key Source IP
Burst capacity 10 attempts per bucket
Refill rate 1 token every 6 seconds, about 10 attempts per minute per bucket
Reservation lifetime Held for the duration of the LDAP bind
Idle entry cleanup Bucket state is removed after 15 minutes without activity
Throttled response HTTP 429, STS code ThrottlingException, Retry-After: 6
Scope Per-node, in-memory, not cluster-wide
Configurability Not currently configurable

In a multi-node deployment behind a load balancer, each Silo node tracks its own buckets. The effective aggregate budget therefore depends on how requests are distributed across nodes.

Trusted proxies

If Silo is deployed behind a trusted reverse proxy, load balancer, or API gateway and you want LDAP STS throttling to bucket by the forwarded client IP instead of the proxy peer address, configure:

MINIO_IDENTITY_LDAP_STS_TRUSTED_PROXIES     (list)      comma/semicolon/whitespace-separated list of trusted proxy IPs or CIDRs

Only requests whose peer address matches this allowlist may supply forwarded client IP headers for LDAP STS rate limiting. Requests from all other peers continue to use the peer address directly. Catch-all ranges (0.0.0.0/0, ::/0) are rejected, since they would trust forwarded headers from every peer.

X-Forwarded-For is parsed right-to-left, skipping addresses that match the trusted-proxy allowlist, and the first untrusted address is used. A client-supplied (left-most) value is therefore ignored unless the entire chain to its right is trusted — so even nginx's default appending proxy_add_x_forwarded_for is safe. List every proxy hop's address in the allowlist so intermediate hops are skipped.

X-Real-IP is preferred over X-Forwarded-For when present, but — unlike X-Forwarded-For — it is a single value that cannot be chain-validated against the allowlist, so it is trusted verbatim. The trusted proxy must overwrite (not pass through) any client-supplied X-Real-IP. If the proxy forwards a client-supplied value, an attacker can send a different X-Real-IP on each request to land in a fresh bucket and bypass per-source throttling. When in doubt, configure the proxy to set X-Real-IP from the connecting peer (e.g. nginx proxy_set_header X-Real-IP $remote_addr), or omit X-Real-IP and rely on the chain-validated X-Forwarded-For.

The RFC 7239 Forwarded header is not used for this bucket; deployments that only send Forwarded fall back to the peer-address bucket.

This allowlist governs LDAP STS rate-limit bucketing only. The client address used for aws:SourceIp, audit logs and event notifications is governed separately by MINIO_API_TRUSTED_PROXIES — see Client source address trust. The two use the same list syntax and the same chain-walking rules, and in most deployments should be set to the same value. They differ deliberately in one respect: this setting prefers X-Real-IP over X-Forwarded-For, while MINIO_API_TRUSTED_PROXIES prefers the chain-validated X-Forwarded-For, because it decides access control rather than rate-limit bucketing. Neither order is safe for every proxy; the linked document explains the trade-off.

Lookup-Bind

A low-privilege read-only LDAP service account is configured in the Silo server by providing the account's Distinguished Name (DN) and password. This service account is used to perform directory lookups as needed.

MINIO_IDENTITY_LDAP_LOOKUP_BIND_DN*          (string)    DN for LDAP read-only service account used to perform DN and group lookups
MINIO_IDENTITY_LDAP_LOOKUP_BIND_PASSWORD     (string)    Password for LDAP read-only service account used to perform DN and group lookups

If you set an empty lookup bind password, the lookup bind will use the unauthenticated authentication mechanism, as described in RFC 4513 Section 5.1.2.

User lookup

When a user provides their LDAP credentials, Silo runs a lookup query to find the user's Distinguished Name (DN). The search filter and base DN used in this lookup query are configured via the following variables:

MINIO_IDENTITY_LDAP_USER_DN_SEARCH_BASE_DN*  (list)      ";" separated list of user search base DNs e.g. "dc=myldapserver,dc=com"
MINIO_IDENTITY_LDAP_USER_DN_SEARCH_FILTER*   (string)    Search filter to lookup user DN

The search filter must use the LDAP username to find the user DN. This is done via variable substitution.

The returned user's DN and their password are then verified with the LDAP server. The user DN may also be associated with an access policy.

The User DN attributes configuration parameter:

MINIO_IDENTITY_LDAP_USER_DN_ATTRIBUTES      (list)      "," separated list of user DN attributes e.g. "uid,cn,mail,sshPublicKey"

is optional and can be used to specify additional attributes to lookup on the User DN record in the LDAP server. This is for certain display purposes and may be used for extended functionality that may be added in the future.

Silo can be optionally configured to find the groups of a user from AD/LDAP by specifying the following variables:

MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER     (string)    search filter for groups e.g. "(&(objectclass=groupOfNames)(memberUid=%s))"
MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN    (list)      ";" separated list of group search base DNs e.g. "dc=myldapserver,dc=com"

The search filter must use the username or the DN to find the user's groups. This is done via variable substitution.

A group's DN may be associated with an access policy.

Nested groups usage in LDAP/AD

If you are using Active directory with nested groups you have to add LDAP_MATCHING_RULE_IN_CHAIN: :1.2.840.113556.1.4.1941: to your query. For example:

group_search_filter: (&(objectClass=group)(member:1.2.840.113556.1.4.1941:=%d))
user_dn_search_filter: (&(memberOf:1.2.840.113556.1.4.1941:=CN=group,DC=dc,DC=net)(sAMAccountName=%s))

Sample settings

Here are some (minimal) sample settings for development or experimentation:

export MINIO_IDENTITY_LDAP_SERVER_ADDR=myldapserver.com:636
export MINIO_IDENTITY_LDAP_LOOKUP_BIND_DN='cn=admin,dc=min,dc=io'
export MINIO_IDENTITY_LDAP_LOOKUP_BIND_PASSWORD=admin
export MINIO_IDENTITY_LDAP_USER_DN_SEARCH_BASE_DN='ou=hwengg,dc=min,dc=io'
export MINIO_IDENTITY_LDAP_USER_DN_SEARCH_FILTER='(uid=%s)'
export MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY=on

Variable substitution in configuration strings

In the configuration variables, %s is substituted with the username from the STS request and %d is substituted with the distinguished username (user DN) of the LDAP user. Please see the following table for which configuration variables support these substitution variables:

Variable Supported substitutions
MINIO_IDENTITY_LDAP_USER_DN_SEARCH_FILTER %s
MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER %s and %d

Managing User/Group Access Policy

Access policies may be associated by their name with a group or user directly. Access policies are first defined on the Silo server using IAM policy JSON syntax. To define a new policy, you can use the AWS policy generator. Copy the policy into a text file mypolicy.json and issue the command like so:

mc admin policy create mysilo mypolicy mypolicy.json

To associate the policy with an LDAP user or group, use the full DN of the user or group:

mc idp ldap policy attach mysilo mypolicy --user='uid=james,cn=accounts,dc=myldapserver,dc=com'
mc idp ldap policy attach mysilo mypolicy ----group='cn=projectx,ou=groups,ou=hwengg,dc=min,dc=io'

To remove a policy association, use the similar detach command:

mc idp ldap policy detach mysilo mypolicy --user='uid=james,cn=accounts,dc=myldapserver,dc=com'
mc idp ldap policy detach mysilo mypolicy ----group='cn=projectx,ou=groups,ou=hwengg,dc=min,dc=io'

Note that the commands above attempt to validate if the given entity (user or group) exist in the LDAP directory and return an error if they are not found.

View **DEPRECATED** older policy association commands

Please do not use these as they may be removed or their behavior may change.

mc admin policy attach mysilo mypolicy --user='uid=james,cn=accounts,dc=myldapserver,dc=com'
mc admin policy attach mysilo mypolicy --group='cn=projectx,ou=groups,ou=hwengg,dc=min,dc=io'

Note that by default no policy is set on a user. Thus even if they successfully authenticate with AD/LDAP credentials, they have no access to object storage as the default access policy is to deny all access.

API Request Parameters

LDAPUsername

Is AD/LDAP username to login. Application must ask user for this value to successfully obtain rotating access credentials from AssumeRoleWithLDAPIdentity.

Params Value
Type String
Length Constraints Minimum length of 2. Maximum length of 2048.
Required Yes

LDAPPassword

Is AD/LDAP username password to login. Application must ask user for this value to successfully obtain rotating access credentials from AssumeRoleWithLDAPIdentity.

Params Value
Type String
Length Constraints Minimum length of 4. Maximum length of 2048.
Required Yes

Version

Indicates STS API version information, the only supported value is '2011-06-15'. This value is borrowed from AWS STS API documentation for compatibility reasons.

Params Value
Type String
Required Yes

DurationSeconds

The duration, in seconds. The value can range from 900 seconds (15 minutes) up to 365 days. If value is higher than this setting, then operation fails. By default, the value is set to 3600 seconds.

Params Value
Type Integer
Valid Range Minimum value of 900. Maximum value of 31536000.
Required No

Policy

An IAM policy in JSON format that you want to use as an inline session policy. This parameter is optional. Passing policies to this operation returns new temporary credentials. The resulting session's permissions are the intersection of the canned policy name and the policy set here. You cannot use this policy to grant more permissions than those allowed by the canned policy name being assumed.

Params Value
Type String
Valid Range Minimum length of 1. Maximum length of 2048.
Required No

Response Elements

XML response for this API is similar to AWS STS AssumeRoleWithWebIdentity

Errors

XML error response for this API is similar to AWS STS AssumeRoleWithWebIdentity

Authentication failures caused by unknown users and invalid passwords intentionally return the same external STS error response to prevent username enumeration via response differentiation (CVE-2026-33419).

Condition HTTP status STS code Notes
Unknown user or invalid password 400 InvalidParameterValue Same response for both cases to prevent username enumeration
LDAP backend, network, or other infrastructure failure 500 InternalError Returned as an upstream/internal failure and logged server-side
Rate limit exhausted 429 ThrottlingException Includes a Retry-After header

Sample POST Request

http://silo.cluster:9000?Action=AssumeRoleWithLDAPIdentity&LDAPUsername=foouser&LDAPPassword=foouserpassword&Version=2011-06-15&DurationSeconds=7200

Sample Response

<?xml version="1.0" encoding="UTF-8"?>
<AssumeRoleWithLDAPIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
  <AssumeRoleWithLDAPIdentityResult>
    <AssumedRoleUser>
      <Arn/>
      <AssumeRoleId/>
    </AssumedRoleUser>
    <Credentials>
      <AccessKeyId>Y4RJU1RNFGK48LGO9I2S</AccessKeyId>
      <SecretAccessKey>sYLRKS1Z7hSjluf6gEbb9066hnx315wHTiACPAjg</SecretAccessKey>
      <Expiration>2019-08-08T20:26:12Z</Expiration>
      <SessionToken>eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJZNFJKVTFSTkZHSzQ4TEdPOUkyUyIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTQxODExMDcxLCJpYXQiOjE1NDE4MDc0NzEsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiYTBiMjc2MjktZWUxYS00M2JmLTg3MzktZjMzNzRhNGNkYmMwIn0.ewHqKVFTaP-j_kgZrcOEKroNUjk10GEp8bqQjxBbYVovV0nHO985VnRESFbcT6XMDDKHZiWqN2vi_ETX_u3Q-w</SessionToken>
    </Credentials>
  </AssumeRoleWithLDAPIdentity>
  <ResponseMetadata/>
</AssumeRoleWithLDAPIdentityResponse>

Using LDAP STS API

With multiple OU hierarchies for users, and multiple group search base DN's.

export MINIO_ROOT_USER=minio
export MINIO_ROOT_PASSWORD=silo123
export MINIO_IDENTITY_LDAP_SERVER_ADDR='my.ldap-active-dir-server.com:636'
export MINIO_IDENTITY_LDAP_LOOKUP_BIND_DN='cn=admin,dc=min,dc=io'
export MINIO_IDENTITY_LDAP_LOOKUP_BIND_PASSWORD=admin
export MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN='dc=minioad,dc=local;dc=somedomain,dc=com'
export MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER='(&(objectclass=groupOfNames)(member=%d))'
silo server ~/test

You can make sure it works appropriately using our example program:

$ go run ldap.go -u foouser -p foopassword

##### Credentials
{
        "accessKey": "NUIBORZYTV2HG2BMRSXR",
        "secretKey": "qQlP5O7CFPc5m5IXf1vYhuVTFj7BRVJqh0FqZ86S",
        "expiration": "2018-08-21T17:10:29-07:00",
        "sessionToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJOVUlCT1JaWVRWMkhHMkJNUlNYUiIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTM0ODk2NjI5LCJpYXQiOjE1MzQ4OTMwMjksImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiNjY2OTZjZTctN2U1Ny00ZjU5LWI0MWQtM2E1YTMzZGZiNjA4In0.eJONnVaSVHypiXKEARSMnSKgr-2mlC2Sr4fEGJitLcJF_at3LeNdTHv0_oHsv6ZZA3zueVGgFlVXMlREgr9LXA"
}

Explore Further