This project is a proof of concept demonstrating how you can use a service account as an identity provider in your stack thanks to its key (Google-managed and/or User-managed).
Here by identity provider, I mean a trusted authority which signs access tokens.
How does it works?
Note: for a complete explanation, please refer to a dedicated article posted on Medium.
This project is composed of 2 components:
- a simple authorization server which produces access tokens in JWT format
- expose a single endpoint:
POST: {hostname}/token
- expose a single endpoint:
- a simple REST API which trusts the authorization server
- expose a single endpoint:
GET: {hostname}/api/v1/games
- expose a single endpoint:
The main subtlety here is that the JWT is signed by a service account key.
Note: both services are exposed via CloudRun
Please find below a typical application workflow:
Tips: if you cannot or don't want to install following tools on your machine, you can connect to your CloudShell environment. Indeed in CloudShell all required softwares are already installed!
- Install gcloud if it is not already installed (visit GCP documentation for instructions):
- Install Terraform if it is not already installed (visit terraform.io for other distributions):
You will need terraform version >= 1.0.0
Note: you can use Docker or tfenv to comply with this requirement
- Install jq if it is not already installed (visit jq documentation for instructions):
You will need at least the following Google-managed roles (if you are not project Owner):
- Cloud Run Admin (roles/run.admin)
- Service Account Admin (roles/iam.serviceAccountAdmin)
- Service Usage Admin (roles/serviceusage.serviceUsageAdmin)
- Secret Manager Admin (roles/secretmanager.admin)
- Artifact Registry Administrator (roles/artifactregistry.admin)
- Cloud Build Editor (roles/cloudbuild.builds.editor)
๐จ Warning: if your project applies the following organization policies, Terraform may not work normally
- Domain restricted sharing: both applications will be setup to be accessible publicly (thanks to
allUsers
IAM policy) that may be forbidden - Disable service account key creation: if this policy is enable Terraform won't be able to create a service account key
- Set the project, replace
YOUR_PROJECT
with your project ID:
PROJECT=YOUR_PROJECT
gcloud config set project ${PROJECT}
- Define global variables:
REGION=europe-west1
ARTIFACT_REGISTRY=sa-as-idp
- Activate required services:
gcloud services enable iam.googleapis.com
gcloud services enable iamcredentials.googleapis.com
gcloud services enable secretmanager.googleapis.com
gcloud services enable cloudbuild.googleapis.com
gcloud services enable artifactregistry.googleapis.com
gcloud services enable run.googleapis.com
- Create docker registry:
gcloud artifacts repositories create $ARTIFACT_REGISTRY --location=$REGION --repository-format=docker
- Create docker images:
# build and push the authorization server
gcloud builds submit --region=$REGION --tag "$REGION-docker.pkg.dev/$PROJECT/$ARTIFACT_REGISTRY/simple-authz-server:latest" ./simple_authorization_server
# build and push the api
gcloud builds submit --region=$REGION --tag "$REGION-docker.pkg.dev/$PROJECT/$ARTIFACT_REGISTRY/simple-api:latest" ./simple_api
- Configure the environment for Terraform:
[[ $CLOUD_SHELL ]] || gcloud auth application-default login
- Initialize Terraform:
cd ./iac
terraform init
In order to perform tests the authorization server have 3 mocked users .
username | password | role |
---|---|---|
alice | strongP@s$w0rd | player |
bob | otherstrongP@s$w0rd | player |
charlie | root | admin |
- Deploy the infrastructure:
terraform apply -auto-approve -var=project_id=$PROJECT -var=region=$REGION -var=registry_name=$ARTIFACT_REGISTRY
- Produce an access token:
# retrieve an access token from the authorization server
ACCESS_TOKEN=$(curl -sS -X POST "$(terraform output -raw authorization_server_url)/token" -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=password&username=alice&password=strongP@s$w0rd' | jq --raw-output .access_token)
echo $ACCESS_TOKEN
null
it's because IAM permissions of the service account attached to the authorization server aren't effective yet. Wait a minute, then repeat the operation in order to get the access token.
- Validate the access token:
# use the access token to authenticate to the api
curl -sS -H "Authorization: Bearer $ACCESS_TOKEN" -X GET "$(terraform output -raw api_url)/api/v1/games" | jq .
- Deploy the infrastructure:
terraform apply -auto-approve -var=project_id=$PROJECT -var=region=$REGION -var=registry_name=$ARTIFACT_REGISTRY -var=use_user_managed_key=true
- Produce and validate the access token:
# retrieve an access token from the authorization server
ACCESS_TOKEN=$(curl -sS -X POST "$(terraform output -raw authorization_server_url)/token" -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=password&username=alice&password=strongP@s$w0rd' | jq --raw-output .access_token)
# use the access token to authenticate to the api
curl -sS -H "Authorization: Bearer $ACCESS_TOKEN" -X GET "$(terraform output -raw api_url)/api/v1/games" | jq .
Destroy all resources with the command below.
gcloud artifacts repositories delete $ARTIFACT_REGISTRY --location=$REGION -q
terraform destroy -auto-approve -var=project_id=$PROJECT -var=region=$REGION