{"id":21355086,"url":"https://github.com/salrashid123/downscoped_token","last_synced_at":"2025-07-30T09:03:02.891Z","repository":{"id":54425276,"uuid":"242776334","full_name":"salrashid123/downscoped_token","owner":"salrashid123","description":"Credential Access Boundary (DownScoped) Tokens on Google Cloud","archived":false,"fork":false,"pushed_at":"2025-04-14T19:02:03.000Z","size":172,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-15T07:15:31.795Z","etag":null,"topics":["google-cloud","google-cloud-platform"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salrashid123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-02-24T15:48:52.000Z","updated_at":"2025-04-14T19:01:59.000Z","dependencies_parsed_at":"2024-12-30T13:24:43.136Z","dependency_job_id":"4c5c7256-a850-4687-91ac-46b2ba384754","html_url":"https://github.com/salrashid123/downscoped_token","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/salrashid123/downscoped_token","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fdownscoped_token","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fdownscoped_token/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fdownscoped_token/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fdownscoped_token/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salrashid123","download_url":"https://codeload.github.com/salrashid123/downscoped_token/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fdownscoped_token/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267842951,"owners_count":24153132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["google-cloud","google-cloud-platform"],"created_at":"2024-11-22T04:15:46.210Z","updated_at":"2025-07-30T09:03:02.842Z","avatar_url":"https://github.com/salrashid123.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Using Credential Access Boundary (DownScoped) Tokens\n\n`Credential Access Boundary` is a policy language that you can use to downscope the accessing power of your GCP short-lived credentials. You can define a Credential Access Boundary that specifies which resources the short-lived credential can access, as well as an upper bound on the permissions that are available on each resource\n\nFor example, if the parent Credential that represents user Alice has Read/Write access to GCS buckets `A`, `B`, `C`, you can exchange the Alice's credential for another credential that still identifies Alice but can only be used for Read against Bucket `A` and `C`.   You can also define an expression based on a partial resource path and prefix (eg, downscope a token with permissions on a specific object in GCS or a path within GCS) \n\n\nDownScoped tokens are normally used in a tokenbroker/exchange service where you can mint a new restricted token to hand to a client. The sample usage and implementations below shows how to generate a downscoped token, extract the raw access_token, and then inject the raw token in another TokenSource.\n\n** NOTE:**\n\n* DownScoped tokens currently only works for certain resources like GCS, GCE and Cloud Resource Manager objects like Projects, Folders and Organizations.\n* The GCS bucket must be enabled with [Uniform bucket-level access](https://cloud.google.com/storage/docs/uniform-bucket-level-access\n\n\n\u003e\u003e\u003e Important, before you go down the road of using downscoped token and token brokers, consider the usecase you're after and if [Privileged Access Manager](https://cloud.google.com/iam/docs/temporary-elevated-access)\n\nalso see \n\n* [Vault Secrets for GCP Credential Access Boundary and Impersonation](https://github.com/salrashid123/vault-plugin-secrets-gcp-cab)\n\n\u003e\u003e \u003e\u003e\u003e **IMPORTANT**  If you are just looking for code samples that generate downscoped tokens, just use the official samples here [https://cloud.google.com/iam/docs/downscoping-short-lived-credentials#exchange-credential-auto](https://cloud.google.com/iam/docs/downscoping-short-lived-credentials#exchange-credential-auto)\n\n\n### Defining a boundary rule:\n\nYou downscope a token by transmitting that token to a google token endpoint along with a boundary rule describing the resources and roles the credential should be restricted to.\n\nThe definition of a boundary rule is just json:\n\n```json\n{\n  \"accessBoundaryRules\": [\n    {\n      \"availableResource\": \"string\",\n      \"availablePermissions\": [\n        \"list\"\n      ],\n      \"availabilityCondition\": {\n        \"title\": \"string\",\n        \"expression\": \"string\"\n      }\n    }\n  ]\n}\n```\n\nwhere\n\n* `AvailableResource` (required)\nThis is the GCP resource (such as organization, folder, project, bucket, etc) to which access may be allowed (and allowed to resources below that resource if applicable). It must be in the format of a GCP Resource Name.\n\n\n* `AvailablePermissions` (required)\nThis is a list of permissions that may be allowed for use on the specified resource or resources below the specified resource. The only supported value is IAM role with syntax: \"inRole:roles/storage.admin\"\n\n* `AvailabilityCondition` (optional)\nThis describes additional fine-grained constraints to apply to the token.  The `expression` parameter describes the resource condition this rule applies to in [CEL Format](https://cloud.google.com/iam/docs/conditions-overview#cel). \n\nAs an example, the following would the token to just `objectViewer` on `BUCKET_2` and specifically an object (prefix) `/foo.txt`\n\n```json\n{\n  \"accessBoundary\" : {\n      \"accessBoundaryRules\" : [\n        {\n          \"availableResource\" : \"//storage.googleapis.com/projects/_/buckets/$BUCKET_2\",\n          \"availablePermissions\": [\"inRole:roles/storage.objectViewer\"],\n          \"availabilityCondition\" : {\n            \"title\" : \"obj-prefixes\",\n            \"expression\" : \"resource.name.startsWith(\\\"projects/_/buckets/$BUCKET_2/objects/foo.txt\\\")\"\n          }\n        }\n      ]\n  }\n}\n```\n\n* `AvailabilityConditions` (optional)\nThis defines restrictions on the resource based on a condition such as the path or prefix within that path.  Use an `availabilityCondition` to define such things as a specific object this downscoped token could access or the path prefix the token has permissions on.\n\n### Exchange the token\n\nYou now need to transmit the original `access_token` and the boundary rule to a google token-exchange endpoint: `https://sts.googleapis.com/v1/token`.  The response JSON will return a new token if the policy file is well formed.  \n\n\n### Usage: curl\n\nAs a quick demonstration of this capability, create two GCS buckets and acquire an `access_token` that you can use to list objects in either bucket.   Exchange that `access_token` for another `access_token` that _can only be used_ on one of the two buckets:\n\n1. Create two buckets:\n\n```bash\nexport PROJECT_ID=`gcloud config get-value core/project`\n\nexport BUCKET_1=$PROJECT_ID-1\nexport BUCKET_2=$PROJECT_ID-1-suffix\n\ngsutil mb gs://$BUCKET_1\ngsutil mb gs://$BUCKET_2\necho \"foo\" \u003e someobject.txt\ngsutil cp someobject.txt gs://$BUCKET_2/\n```\n\n2. Create policy to only allow `storage.objectViewer` to `BUCKET_2` AND on object `/someobject.txt`\n\n```bash\ncat \u003c\u003cEOF \u003e access_boundary_2.json\n{\n  \"accessBoundary\" : {\n      \"accessBoundaryRules\" : [\n        {\n          \"availableResource\" : \"//storage.googleapis.com/projects/_/buckets/$BUCKET_2\",\n          \"availablePermissions\": [\"inRole:roles/storage.objectViewer\"],\n          \"availabilityCondition\" : {\n            \"title\" : \"obj-prefixes\",\n            \"expression\" : \"resource.name.startsWith(\\\"projects/_/buckets/$BUCKET_2/objects/someobject.txt\\\")\"\n          }\n        }\n      ]\n  }\n}\n\nEOF\n```\n\n3. Get existing `access_token`\n\n```\nexport TOKEN=`gcloud auth application-default print-access-token`\n```\n\n4. Exchange `access_token`\n\n(the following command uses [jq](https://stedolan.github.io/jq/download/) to parse the response):\n\n```bash\nNEW_TOKEN_1=`curl -s -H \"Content-Type:application/x-www-form-urlencoded\" -X POST https://sts.googleapis.com/v1/token -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange\u0026subject_token_type=urn:ietf:params:oauth:token-type:access_token\u0026requested_token_type=urn:ietf:params:oauth:token-type:access_token\u0026subject_token='$TOKEN --data-urlencode \"options=$(cat access_boundary_2.json)\" | jq -r '.access_token'`\n```\n\n5. Use downscoped token\n\nTry listing bucket contents using the new token...\n\nas you'll see, you can access `BUCKET_2` but not `BUCKET_1` since we're using the downscoped token\n```bash\ncurl -s -H \"Authorization: Bearer $NEW_TOKEN_1\"  -o /dev/null  -w \"%{http_code}\\n\" https://storage.googleapis.com/storage/v1/b/$BUCKET_1/o\n\ncurl -s -H \"Authorization: Bearer $NEW_TOKEN_1\"  -o /dev/null  -w \"%{http_code}\\n\" https://storage.googleapis.com/storage/v1/b/$BUCKET_2/o\n```\n\n### Usecase: TokenBroker\n\n1. A developer or workload (the requester) requests credentials to get access to certain GCP resources.\n2. The broker system identifies the service account that has access to the requested resources and gets a credential for that service account.\n3. Before handing off the credentials to the requestor, the broker system restricts the permissions on the credential to only what the token requester needs access to, by applying a `Credential Access Boundary` on the service account credentials by calling the CAB API.\n4. The broker system hands the downscoped credentials to the requester.\n5. The requester can now use those credentials to access GCP resources\n\nThis release has the following restrictions:\n\n\n![images/tokenflow.png](images/tokenflow.png)\n\n---\n\n\nThats it...this is just an alpha capability...do not use this in production yet!.  Again, the intent of this article is to get feedback...please add in any comments to the repo here [https://github.com/salrashid123/downscoped_token](https://github.com/salrashid123/downscoped_token):\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fdownscoped_token","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalrashid123%2Fdownscoped_token","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fdownscoped_token/lists"}