$ mkdir rbac
cd rbac
git init
Initialized empty Git repository in /home/johnandersen777/.tmp/tmp.pVjmEYIeok/rbac/.git/
$ vim setup.sh
$ bash -xe !$
bash -xe setup.sh
+ mkdir policies
+ mkdir roles
+ mkdir droplet-roles
+ tee policies/ex-database-and-spaces-keys-access.hcl
path "/v1/oidc/issue" {
capabilities = ["create"]
allowed_parameters = {
"aud" = "api://DigitalOcean?actx={actx}"
"sub" = "actx:{actx}:role:database-and-spaces-keys-access"
"ttl" = 300
}
}
+ tee droplet-roles/ex-database-and-spaces-keys-access.hcl
role "ex-database-and-spaces-keys-access" {
aud = "api://DigitalOcean?actx={actx}"
sub = "actx:{actx}:role:ex-database-and-spaces-keys-access"
policies = ["ex-database-and-spaces-keys-access"]
}
+ tee policies/database-credential-read.hcl
path "/v2/databases/d4c0539c-1590-4cf7-9f21-361f79cf8361" {
# Enable read of a single database by UUID.
capabilities = ["read"]
}
path "/v2/databases" {
# Enable read of databases tagged with given tag name.
# ? is used for query parameters.
capabilities = ["read"]
allowed_parameters = {
"?" = {
"tag_name" = "my-tag"
}
}
}
+ tee policies/spaces-keys.hcl
path "/v2/spaces/keys" {
# Enable creation of Spaces keys to access a named bucket.
# Allowed parameters not in the top level ? key are treated
# as POST body keys whose values must match hcl defined values.
capabilities = ["create"]
allowed_parameters = {
"name" = "bucket-111-read-token-*"
"grants" = [
{
"bucket" = "111"
"permission" = "read"
}
]
}
}
path "/v2/spaces/keys/*" {
# Enable deletion of Spaces keys.
capabilities = ["delete"]
}
+ tee roles/database-and-spaces-keys-access.hcl
role "database-and-spaces-keys-access" {
aud = "api://DigitalOcean?actx={actx}"
sub = "actx:{actx}:role:database-and-spaces-keys-access"
policies = ["database-credential-read", "spaces-keys"]
}
+ export THIS_ENDPOINT=https://droplet-oidc-poc-2-dwyva.ondigitalocean.app
+ THIS_ENDPOINT=https://droplet-oidc-poc-2-dwyva.ondigitalocean.app
+ mkdir -p /home/johnandersen777/.local/scripts/
+ tee /home/johnandersen777/.local/scripts/git-credential-rbac-digitalocean.sh
#!/usr/bin/env bash
TOKEN=$(doctl auth token)
while IFS='=' read -r key value; do
if [[ -n "$key" && -n "$value" ]]; then
if [[ "$key" == "protocol" || "$key" == "host" ]]; then
echo "$key=$value"
fi
fi
done
echo "username=token"
# https://git-scm.com/docs/git-credential documents how this style of
# script works, stdin / stdout is used for communication to / from git
# and the bash process executing this script. Since we always use the
# doctl local PAT for authentication to this PoC deployment, we don't need
# to add custom logic around if this host or if this protocol, we always
# use the token for the deployed FQDN (git config --global
# credential."${THIS_ENDPOINT}".helper)
echo "password=${TOKEN}"
+ chmod 700 /home/johnandersen777/.local/scripts/git-credential-rbac-digitalocean.sh
+ git init
Reinitialized existing Git repository in /home/johnandersen777/.tmp/tmp.pVjmEYIeok/rbac/.git/
+ git config --global credential.https://droplet-oidc-poc-2-dwyva.ondigitalocean.app.helper '!/home/johnandersen777/.local/scripts/git-credential-rbac-digitalocean.sh'
+ git branch -M main
+ git add .
+ git commit -sm 'feat: configure access from droplet'
[main (root-commit) 71c5e4c] feat: configure access from droplet
6 files changed, 165 insertions(+)
create mode 100644 droplet-roles/ex-database-and-spaces-keys-access.hcl
create mode 100644 policies/database-credential-read.hcl
create mode 100644 policies/ex-database-and-spaces-keys-access.hcl
create mode 100644 policies/spaces-keys.hcl
create mode 100644 roles/database-and-spaces-keys-access.hcl
create mode 100644 setup.sh
+ git remote add deploy https://droplet-oidc-poc-2-dwyva.ondigitalocean.app
+ git push -u deploy main
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 16 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 2.71 KiB | 2.71 MiB/s, done.
Total 11 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
To https://droplet-oidc-poc-2-dwyva.ondigitalocean.app
* [new branch] main -> main
branch 'main' set up to track 'deploy/main'.
+ git fetch --all
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 1017 bytes | 1017.00 KiB/s, done.
From https://droplet-oidc-poc-2-dwyva.ondigitalocean.app
* [new branch] schema -> deploy/schema
+ git show deploy/schema:rbac.json
+ jq
{
"custom_claims_roles_index": {
"job_workflow_ref": {}
},
"policies": {
"database-credential-read": {
"meta": {
"policy": "database-credential-read"
},
"schemas": {
"/v2/databases": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"additionalProperties": false,
"properties": {
"?": {
"const": {
"tag_name": "my-tag"
},
"type": "object"
}
},
"required": [
"?"
],
"type": "object"
},
"capability": {
"enum": [
"read"
]
}
},
"required": [
"capability"
],
"type": "object"
},
"/v2/databases/d4c0539c-1590-4cf7-9f21-361f79cf8361": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"capability": {
"enum": [
"read"
]
}
},
"required": [
"capability"
],
"type": "object"
}
}
},
"ex-database-and-spaces-keys-access": {
"meta": {
"policy": "ex-database-and-spaces-keys-access"
},
"schemas": {
"/v1/oidc/issue": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"additionalProperties": false,
"properties": {
"aud": {
"const": "api://DigitalOcean?actx=4959ec0923473bf22bddd7bec2caf58a294ee007",
"type": "string"
},
"sub": {
"const": "actx:4959ec0923473bf22bddd7bec2caf58a294ee007:role:database-and-spaces-keys-access",
"type": "string"
},
"ttl": {
"const": 300,
"type": "number"
}
},
"required": [
"aud",
"sub",
"ttl"
],
"type": "object"
},
"capability": {
"enum": [
"create"
]
}
},
"required": [
"capability"
],
"type": "object"
}
}
},
"spaces-keys": {
"meta": {
"policy": "spaces-keys"
},
"schemas": {
"/v2/spaces/keys": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"body": {
"additionalProperties": false,
"properties": {
"grants": {
"items": {
"anyOf": [
{
"additionalProperties": false,
"properties": {
"bucket": {
"const": "111"
},
"permission": {
"const": "read"
}
},
"required": [
"bucket",
"permission"
],
"type": "object"
}
]
},
"type": "array"
},
"name": {
"pattern": "bucket-111-read-token-.*",
"type": "string"
}
},
"required": [
"grants",
"name"
],
"type": "object"
},
"capability": {
"enum": [
"create"
]
}
},
"required": [
"capability"
],
"type": "object"
},
"/v2/spaces/keys/*": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"capability": {
"enum": [
"delete"
]
}
},
"required": [
"capability"
],
"type": "object"
}
}
}
},
"roles": {
"database-and-spaces-keys-access": {
"definition": {
"aud": "api://DigitalOcean?actx=4959ec0923473bf22bddd7bec2caf58a294ee007",
"policies": [
"database-credential-read",
"spaces-keys"
],
"sub": "actx:4959ec0923473bf22bddd7bec2caf58a294ee007:role:database-and-spaces-keys-access"
},
"role_name": "database-and-spaces-keys-access"
},
"ex-database-and-spaces-keys-access": {
"definition": {
"aud": "api://DigitalOcean?actx=4959ec0923473bf22bddd7bec2caf58a294ee007",
"policies": [
"ex-database-and-spaces-keys-access"
],
"sub": "actx:4959ec0923473bf22bddd7bec2caf58a294ee007:role:ex-database-and-spaces-keys-access"
},
"role_name": "ex-database-and-spaces-keys-access"
}
}
}
$ doctl \
--api-url "https://droplet-oidc-poc-2-dwyva.ondigitalocean.app" \
compute droplet create \
--region sfo2 \
--size s-1vcpu-1gb \
--image ubuntu-24-04-x64 \
--tag-names "oidc-sub:role:ex-database-and-spaces-keys-access" \
test-droplet-0001
ID Name Public IPv4 Private IPv4 Public IPv6 Memory VCPUs Disk Region Image VPC UUID Status Tags Features Volumes
577242657 test-droplet-0001 1024 1 25 sfo2 Ubuntu 24.04 (LTS) x64 new oidc-sub:role:ex-database-and-spaces-keys-access droplet_agent
$ doctl compute d list
ID Name Public IPv4 Private IPv4 Public IPv6 Memory VCPUs Disk Region Image VPC UUID Status Tags Features Volumes
577242657 test-droplet-0001 157.245.234.20 10.138.0.3 1024 1 25 sfo2 Ubuntu 24.04 (LTS) x64 5ea03263-94e8-489e-85e6-c64128ef9a71 active oidc-sub:role:ex-database-and-spaces-keys-access droplet_agent,private_networking
$ ssh root@157.245.234.20
The authenticity of host '157.245.234.20 (157.245.234.20)' can't be established.
ED25519 key fingerprint is: SHA256:EYEq0qJubqeraFQU0SF9lMsFYg0AGsMZyt+rJyXBlHs
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '157.245.234.20' (ED25519) to the list of known hosts.
Welcome to Ubuntu 24.04.3 LTS (GNU/Linux 6.8.0-71-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Fri Jun 12 19:01:12 UTC 2026
System load: 0.75 Processes: 109
Usage of /: 8.2% of 23.17GB Users logged in: 0
Memory usage: 23% IPv4 address for eth0: 157.245.234.20
Swap usage: 0% IPv4 address for eth0: 10.46.0.6
Expanded Security Maintenance for Applications is not enabled.
198 updates can be applied immediately.
150 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
root@test-droplet-0001:~# URL=$(cat /root/secrets/digitalocean.com/serviceaccount/base_url)
TEAM_UUID=$(cat /root/secrets/digitalocean.com/serviceaccount/team_uuid)
ID_TOKEN=$(cat /root/secrets/digitalocean.com/serviceaccount/token)
root@test-droplet-0001:~# SUBJECT="actx:${TEAM_UUID}:role:database-and-spaces-keys-access"
TOKEN=$(curl -sf \
-H "Authorization: Bearer ${ID_TOKEN}" \
-d@<(jq -n -c \
--arg aud "api://DigitalOcean?actx=${TEAM_UUID}" \
--arg sub "${SUBJECT}" \
--arg ttl 300 \
'{aud: $aud, sub: $sub, ttl: ($ttl | fromjson)}') \
"${URL}/v1/oidc/issue" \
| jq -r .token)
root@test-droplet-0001:~# DATABASE_UUID=d4c0539c-1590-4cf7-9f21-361f79cf8361
root@test-droplet-0001:~#
curl -sf \
-H "Authorization: Bearer ${TOKEN}" \
"${URL}/v2/databases/${DATABASE_UUID}" \
| jq -r .database.connection.uri
https://doadmin:REDACTEDcNQDREDACTEDuYFQ@compute-contracts-0001-do-user-6349623-0.j.db.ondigitalocean.com:25060
Created
June 12, 2026 19:07
-
-
Save johnandersen777/15f8eb181529024ca485c39be6bfaacc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| mkdir policies | |
| mkdir roles | |
| mkdir droplet-roles | |
| tee policies/ex-database-and-spaces-keys-access.hcl <<'EOF' | |
| path "/v1/oidc/issue" { | |
| capabilities = ["create"] | |
| allowed_parameters = { | |
| "aud" = "api://DigitalOcean?actx={actx}" | |
| "sub" = "actx:{actx}:role:database-and-spaces-keys-access" | |
| "ttl" = 300 | |
| } | |
| } | |
| EOF | |
| tee droplet-roles/ex-database-and-spaces-keys-access.hcl <<'EOF' | |
| role "ex-database-and-spaces-keys-access" { | |
| aud = "api://DigitalOcean?actx={actx}" | |
| sub = "actx:{actx}:role:ex-database-and-spaces-keys-access" | |
| policies = ["ex-database-and-spaces-keys-access"] | |
| } | |
| EOF | |
| tee policies/database-credential-read.hcl <<'EOF' | |
| path "/v2/databases/d4c0539c-1590-4cf7-9f21-361f79cf8361" { | |
| # Enable read of a single database by UUID. | |
| capabilities = ["read"] | |
| } | |
| path "/v2/databases" { | |
| # Enable read of databases tagged with given tag name. | |
| # ? is used for query parameters. | |
| capabilities = ["read"] | |
| allowed_parameters = { | |
| "?" = { | |
| "tag_name" = "my-tag" | |
| } | |
| } | |
| } | |
| EOF | |
| tee policies/spaces-keys.hcl <<'EOF' | |
| path "/v2/spaces/keys" { | |
| # Enable creation of Spaces keys to access a named bucket. | |
| # Allowed parameters not in the top level ? key are treated | |
| # as POST body keys whose values must match hcl defined values. | |
| capabilities = ["create"] | |
| allowed_parameters = { | |
| "name" = "bucket-111-read-token-*" | |
| "grants" = [ | |
| { | |
| "bucket" = "111" | |
| "permission" = "read" | |
| } | |
| ] | |
| } | |
| } | |
| path "/v2/spaces/keys/*" { | |
| # Enable deletion of Spaces keys. | |
| capabilities = ["delete"] | |
| } | |
| EOF | |
| tee roles/database-and-spaces-keys-access.hcl <<'EOF' | |
| role "database-and-spaces-keys-access" { | |
| aud = "api://DigitalOcean?actx={actx}" | |
| sub = "actx:{actx}:role:database-and-spaces-keys-access" | |
| policies = ["database-credential-read", "spaces-keys"] | |
| } | |
| EOF | |
| # Define the FQDN of your deployed API proxy | |
| export THIS_ENDPOINT="https://droplet-oidc-poc-2-dwyva.ondigitalocean.app" | |
| mkdir -p "${HOME}/.local/scripts/" | |
| tee "${HOME}/.local/scripts/git-credential-rbac-digitalocean.sh" <<'EOF' | |
| #!/usr/bin/env bash | |
| TOKEN=$(doctl auth token) | |
| while IFS='=' read -r key value; do | |
| if [[ -n "$key" && -n "$value" ]]; then | |
| if [[ "$key" == "protocol" || "$key" == "host" ]]; then | |
| echo "$key=$value" | |
| fi | |
| fi | |
| done | |
| echo "username=token" | |
| # https://git-scm.com/docs/git-credential documents how this style of | |
| # script works, stdin / stdout is used for communication to / from git | |
| # and the bash process executing this script. Since we always use the | |
| # doctl local PAT for authentication to this PoC deployment, we don't need | |
| # to add custom logic around if this host or if this protocol, we always | |
| # use the token for the deployed FQDN (git config --global | |
| # credential."${THIS_ENDPOINT}".helper) | |
| echo "password=${TOKEN}" | |
| EOF | |
| chmod 700 "${HOME}/.local/scripts/git-credential-rbac-digitalocean.sh" | |
| git init | |
| git config --global credential."${THIS_ENDPOINT}".helper \ | |
| '!'"${HOME}/.local/scripts/git-credential-rbac-digitalocean.sh" | |
| git branch -M main | |
| git add . | |
| git commit -sm "feat: configure access from droplet" | |
| git remote add deploy "${THIS_ENDPOINT}" | |
| git push -u deploy main | |
| # View deployed config | |
| git fetch --all && git show deploy/schema:rbac.json | jq |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment