Add authenticated endpoint.
This commit is contained in:
19
terraform/.terraform.lock.hcl
generated
19
terraform/.terraform.lock.hcl
generated
@@ -60,3 +60,22 @@ provider "registry.terraform.io/hashicorp/random" {
|
||||
"zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/tls" {
|
||||
version = "4.0.6"
|
||||
hashes = [
|
||||
"h1:dYSb3V94K5dDMtrBRLPzBpkMTPn+3cXZ/kIJdtFL+2M=",
|
||||
"zh:10de0d8af02f2e578101688fd334da3849f56ea91b0d9bd5b1f7a243417fdda8",
|
||||
"zh:37fc01f8b2bc9d5b055dc3e78bfd1beb7c42cfb776a4c81106e19c8911366297",
|
||||
"zh:4578ca03d1dd0b7f572d96bd03f744be24c726bfd282173d54b100fd221608bb",
|
||||
"zh:6c475491d1250050765a91a493ef330adc24689e8837a0f07da5a0e1269e11c1",
|
||||
"zh:81bde94d53cdababa5b376bbc6947668be4c45ab655de7aa2e8e4736dfd52509",
|
||||
"zh:abdce260840b7b050c4e401d4f75c7a199fafe58a8b213947a258f75ac18b3e8",
|
||||
"zh:b754cebfc5184873840f16a642a7c9ef78c34dc246a8ae29e056c79939963c7a",
|
||||
"zh:c928b66086078f9917aef0eec15982f2e337914c5c4dbc31dd4741403db7eb18",
|
||||
"zh:cded27bee5f24de6f2ee0cfd1df46a7f88e84aaffc2ecbf3ff7094160f193d50",
|
||||
"zh:d65eb3867e8f69aaf1b8bb53bd637c99c6b649ba3db16ded50fa9a01076d1a27",
|
||||
"zh:ecb0c8b528c7a619fa71852bb3fb5c151d47576c5aab2bf3af4db52588722eeb",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -11,8 +11,41 @@ resource "google_cloud_run_v2_service" "api_server" {
|
||||
ports {
|
||||
container_port = 8080
|
||||
}
|
||||
env {
|
||||
name = "JWT_PUBLIC_KEY"
|
||||
value = tls_private_key.jwt_private_key.public_key_pem
|
||||
}
|
||||
env {
|
||||
name = "JWT_PRIVATE_KEY"
|
||||
value_source {
|
||||
secret_key_ref {
|
||||
secret = google_secret_manager_secret.jwt_private_key.secret_id
|
||||
version = "latest"
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "JWT_CLIENT_ID"
|
||||
value = random_uuid.jwt_client_id.result
|
||||
}
|
||||
env {
|
||||
name = "JWT_GATEWAY_ADDRESS"
|
||||
value = "gateway-to-the-api-etf4fzq.uc.gateway.dev"
|
||||
# value = google_api_gateway_gateway.gateway.default_hostname
|
||||
# TODO: This causes a cycle. Perhaps cloud run has a default env variable with this information.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [google_project_service.service["run"], ]
|
||||
}
|
||||
|
||||
resource "google_cloud_run_service_iam_binding" "public" {
|
||||
project = google_cloud_run_v2_service.api_server.project
|
||||
location = google_cloud_run_v2_service.api_server.location
|
||||
service = google_cloud_run_v2_service.api_server.name
|
||||
role = "roles/run.invoker"
|
||||
members = [
|
||||
"allUsers"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
resource "random_uuid" "jwt_client_id" {
|
||||
}
|
||||
|
||||
resource "google_api_gateway_api" "api" {
|
||||
provider = google-beta
|
||||
project = google_project.project.project_id
|
||||
@@ -13,31 +16,8 @@ resource "google_api_gateway_api_config" "api_config" {
|
||||
|
||||
openapi_documents {
|
||||
document {
|
||||
path = "spec.yaml"
|
||||
contents = base64encode(<<-EOF
|
||||
swagger: "2.0"
|
||||
info:
|
||||
title: the-gateway foo
|
||||
description: "Run auth through Google API Gateway."
|
||||
version: "1.0.0"
|
||||
schemes:
|
||||
- "https"
|
||||
produces:
|
||||
- application/json
|
||||
x-google-backend:
|
||||
address: ${google_cloud_run_v2_service.api_server.uri}
|
||||
paths:
|
||||
"/":
|
||||
get:
|
||||
description: "Hello World."
|
||||
operationId: "helloWorld"
|
||||
responses:
|
||||
200:
|
||||
description: "Success."
|
||||
schema:
|
||||
type: string
|
||||
EOF
|
||||
)
|
||||
path = "spec.yaml"
|
||||
contents = base64encode(templatefile("openapi_spec.yaml", { backend_url = google_cloud_run_v2_service.api_server.uri, client_id = random_uuid.jwt_client_id.result }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,9 +27,20 @@ resource "google_api_gateway_gateway" "gateway" {
|
||||
project = google_project.project.project_id
|
||||
api_config = google_api_gateway_api_config.api_config.id
|
||||
gateway_id = "gateway-to-the-api"
|
||||
# Delete this when api_config changes, otherwise if api_config needs to be replaced, it errors out because it is "in use" by this gateway. I wish this could be triggered only when api_config is being replaced instead of all edits.
|
||||
lifecycle {
|
||||
replace_triggered_by = [
|
||||
google_api_gateway_api_config.api_config
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
output "gateway_address" {
|
||||
value = google_api_gateway_gateway.gateway.default_hostname
|
||||
}
|
||||
|
||||
output "client_id" {
|
||||
value = random_uuid.jwt_client_id.result
|
||||
}
|
||||
|
||||
39
terraform/jwt_key.tf
Normal file
39
terraform/jwt_key.tf
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Warning: This file contains terraform that will lead to secrets being stored in the terraform state file unencrypted. It is not suitable for a production deploy, but since this is a test/experiment, the additional automation outweighed the potential risk.
|
||||
#
|
||||
|
||||
resource "tls_private_key" "jwt_private_key" {
|
||||
algorithm = "RSA"
|
||||
rsa_bits = 2048
|
||||
}
|
||||
|
||||
resource "google_secret_manager_secret" "jwt_private_key" {
|
||||
project = google_project.project.project_id
|
||||
secret_id = "jwt-private-key"
|
||||
|
||||
replication {
|
||||
auto {}
|
||||
}
|
||||
|
||||
depends_on = [google_project_service.service["secretmanager"], ]
|
||||
}
|
||||
|
||||
|
||||
resource "google_secret_manager_secret_version" "jwt_private_key" {
|
||||
secret = google_secret_manager_secret.jwt_private_key.id
|
||||
|
||||
secret_data = tls_private_key.jwt_private_key.private_key_pem
|
||||
}
|
||||
|
||||
resource "google_secret_manager_secret_iam_member" "member" {
|
||||
project = google_secret_manager_secret.jwt_private_key.project
|
||||
secret_id = google_secret_manager_secret.jwt_private_key.secret_id
|
||||
role = "roles/secretmanager.secretAccessor"
|
||||
member = "serviceAccount:${google_project.project.number}-compute@developer.gserviceaccount.com"
|
||||
# TODO: This should probably be using a service account specific to the cloud run service instead of the compute service agent.
|
||||
}
|
||||
|
||||
output "jwt_private_key" {
|
||||
value = tls_private_key.jwt_private_key.private_key_pem
|
||||
sensitive = true
|
||||
}
|
||||
@@ -74,7 +74,7 @@ resource "google_project" "project" {
|
||||
|
||||
resource "google_project_service" "service" {
|
||||
project = google_project.project.project_id
|
||||
for_each = toset(["run", "artifactregistry", "apigateway"])
|
||||
for_each = toset(["run", "artifactregistry", "apigateway", "secretmanager"])
|
||||
service = "${each.key}.googleapis.com"
|
||||
disable_dependent_services = true
|
||||
}
|
||||
|
||||
61
terraform/openapi_spec.yaml
Normal file
61
terraform/openapi_spec.yaml
Normal file
@@ -0,0 +1,61 @@
|
||||
swagger: "2.0"
|
||||
info:
|
||||
title: the-gateway foo
|
||||
description: "Run auth through Google API Gateway."
|
||||
version: "1.0.0"
|
||||
schemes:
|
||||
- "https"
|
||||
produces:
|
||||
- application/json
|
||||
x-google-backend:
|
||||
address: ${backend_url}
|
||||
paths:
|
||||
"/":
|
||||
get:
|
||||
description: "Hello World."
|
||||
operationId: "helloWorld"
|
||||
responses:
|
||||
200:
|
||||
description: "Success."
|
||||
schema:
|
||||
type: string
|
||||
"/.well-known/jwks.json":
|
||||
get:
|
||||
description: "JWKS."
|
||||
operationId: "jwks"
|
||||
responses:
|
||||
200:
|
||||
description: "Success."
|
||||
schema:
|
||||
type: string
|
||||
"/some_protected_endpoint":
|
||||
get:
|
||||
description: "An endpoint that requires auth."
|
||||
operationId: "someProtectedEndpoint"
|
||||
security:
|
||||
- your_custom_auth_id: []
|
||||
responses:
|
||||
200:
|
||||
description: "Success."
|
||||
schema:
|
||||
type: string
|
||||
"/get_short_lived_token":
|
||||
get:
|
||||
description: "An endpoint that gives a short-lived JWT."
|
||||
operationId: "getShortLivedToken"
|
||||
security:
|
||||
- your_custom_auth_id: []
|
||||
responses:
|
||||
200:
|
||||
description: "Success."
|
||||
schema:
|
||||
type: string
|
||||
securityDefinitions:
|
||||
your_custom_auth_id:
|
||||
authorizationUrl: ""
|
||||
flow: "implicit"
|
||||
type: "oauth2"
|
||||
# The value below should be unique
|
||||
x-google-issuer: "issuer of the token"
|
||||
x-google-jwks_uri: "${backend_url}/.well-known/jwks.json"
|
||||
x-google-audiences: "${client_id}"
|
||||
Reference in New Issue
Block a user