Add authenticated endpoint.
This commit is contained in:
parent
f9d3c551f0
commit
9ea4952327
29
api_server/api_server/jwks_schema.py
Normal file
29
api_server/api_server/jwks_schema.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import Literal, Annotated, Union
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseJwks(BaseModel):
|
||||||
|
keys: list[ResponseJwk]
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseRsaJwk(BaseModel):
|
||||||
|
kty: Literal["RSA"]
|
||||||
|
d: str | None = Field(default=None)
|
||||||
|
q: str | None = Field(default=None)
|
||||||
|
qi: str | None = Field(default=None)
|
||||||
|
dq: str | None = Field(default=None)
|
||||||
|
e: str | None = Field(default=None)
|
||||||
|
key_ops: list[str] | None = Field(default=None)
|
||||||
|
dp: str | None = Field(default=None)
|
||||||
|
n: str | None = Field(default=None)
|
||||||
|
p: str | None = Field(default=None)
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseEcJwk(BaseModel):
|
||||||
|
kty: Literal["EC"]
|
||||||
|
|
||||||
|
|
||||||
|
ResponseJwk = Annotated[
|
||||||
|
Union[ResponseRsaJwk, ResponseEcJwk], Field(discriminator="kty")
|
||||||
|
]
|
40
api_server/api_server/local_generate_long_lived_token.py
Normal file
40
api_server/api_server/local_generate_long_lived_token.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import jwt
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
gateway_address = get_terraform_output("gateway_address")
|
||||||
|
client_id = get_terraform_output("client_id")
|
||||||
|
jwt_private_key = get_terraform_output("jwt_private_key")
|
||||||
|
private_key = serialization.load_pem_private_key(
|
||||||
|
jwt_private_key.encode("utf-8"), password=None, backend=default_backend()
|
||||||
|
)
|
||||||
|
encoded = jwt.encode(
|
||||||
|
{
|
||||||
|
"iss": "issuer of the token",
|
||||||
|
"sub": "Alice",
|
||||||
|
"aud": client_id,
|
||||||
|
"iat": int(time.time()),
|
||||||
|
"exp": int(time.time()) + 30 * 60 * 60 * 24,
|
||||||
|
},
|
||||||
|
private_key,
|
||||||
|
algorithm="RS256",
|
||||||
|
)
|
||||||
|
print(encoded)
|
||||||
|
|
||||||
|
|
||||||
|
def get_terraform_output(name: str) -> str:
|
||||||
|
terraform_folder = Path(__file__).parent / "../../terraform"
|
||||||
|
result = subprocess.run(
|
||||||
|
["terraform", f"-chdir={terraform_folder}", "output", "-raw", name],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
return result.stdout.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -1,4 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
import jwt.algorithms
|
||||||
|
import jwt
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from functools import cache
|
||||||
|
import os
|
||||||
|
from api_server.jwks_schema import ResponseJwks, ResponseRsaJwk
|
||||||
|
import time
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
@ -6,3 +15,47 @@ app = FastAPI()
|
|||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def root():
|
async def root():
|
||||||
return {"message": "Hello World"}
|
return {"message": "Hello World"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/some_protected_endpoint")
|
||||||
|
async def protected_endpoint():
|
||||||
|
# TODO: Read X-Apigateway-Api-Userinfo header
|
||||||
|
return {"message": "You reached the protected endpoint"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/get_short_lived_token")
|
||||||
|
async def get_short_lived_token():
|
||||||
|
gateway_address = os.environ["JWT_GATEWAY_ADDRESS"]
|
||||||
|
client_id = os.environ["JWT_CLIENT_ID"]
|
||||||
|
jwt_private_key = os.environ["JWT_PRIVATE_KEY"]
|
||||||
|
private_key = serialization.load_pem_private_key(
|
||||||
|
jwt_private_key.encode("utf-8"), password=None, backend=default_backend()
|
||||||
|
)
|
||||||
|
encoded = jwt.encode(
|
||||||
|
{
|
||||||
|
"iss": "issuer of the token",
|
||||||
|
"sub": "Alice",
|
||||||
|
"aud": client_id,
|
||||||
|
"iat": int(time.time()),
|
||||||
|
"exp": int(time.time()) + 5 * 60,
|
||||||
|
},
|
||||||
|
private_key,
|
||||||
|
algorithm="RS256",
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"message": "This JWT will only last 5 minutes.", "token": encoded}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/.well-known/jwks.json")
|
||||||
|
async def jwks() -> ResponseJwks:
|
||||||
|
return _generate_jwks()
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def _generate_jwks() -> ResponseJwks:
|
||||||
|
private_key_pem = os.environ["JWT_PRIVATE_KEY"]
|
||||||
|
private_key = serialization.load_pem_private_key(
|
||||||
|
private_key_pem.encode("utf-8"), password=None, backend=default_backend()
|
||||||
|
)
|
||||||
|
jwk_json = jwt.algorithms.RSAAlgorithm.to_jwk(private_key)
|
||||||
|
return ResponseJwks(keys=[ResponseRsaJwk.model_validate_json(jwk_json)])
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
FROM alpine:3.20 AS builder
|
ARG ALPINE_VERSION="3.20"
|
||||||
|
|
||||||
|
FROM alpine:${ALPINE_VERSION} AS builder
|
||||||
|
|
||||||
RUN apk add --no-cache python3 poetry py3-poetry-plugin-export
|
RUN apk add --no-cache python3 poetry py3-poetry-plugin-export
|
||||||
|
|
||||||
@ -10,7 +12,7 @@ RUN poetry export --output=requirements.txt
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:3.20 AS runner
|
FROM alpine:${ALPINE_VERSION} AS runner
|
||||||
|
|
||||||
RUN addgroup web && adduser -D -G web web && install -d -D -o web -g web -m 700 /source
|
RUN addgroup web && adduser -D -G web web && install -d -D -o web -g web -m 700 /source
|
||||||
WORKDIR /source
|
WORKDIR /source
|
||||||
|
158
api_server/poetry.lock
generated
158
api_server/poetry.lock
generated
@ -75,6 +75,85 @@ d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
|
|||||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||||
uvloop = ["uvloop (>=0.15.2)"]
|
uvloop = ["uvloop (>=0.15.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "1.17.1"
|
||||||
|
description = "Foreign Function Interface for Python calling C code."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
|
||||||
|
{file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
|
||||||
|
{file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
|
||||||
|
{file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
|
||||||
|
{file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
|
||||||
|
{file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
|
||||||
|
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
|
||||||
|
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pycparser = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.1.7"
|
version = "8.1.7"
|
||||||
@ -100,6 +179,55 @@ files = [
|
|||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cryptography"
|
||||||
|
version = "43.0.1"
|
||||||
|
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
|
||||||
|
{file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
|
||||||
|
{file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
|
||||||
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
|
||||||
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
|
||||||
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
|
||||||
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
|
||||||
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
|
||||||
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
|
||||||
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
|
||||||
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
|
||||||
|
{file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
|
||||||
|
docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||||
|
nox = ["nox"]
|
||||||
|
pep8test = ["check-sdist", "click", "mypy", "ruff"]
|
||||||
|
sdist = ["build"]
|
||||||
|
ssh = ["bcrypt (>=3.1.5)"]
|
||||||
|
test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
||||||
|
test-randomorder = ["pytest-randomly"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastapi"
|
name = "fastapi"
|
||||||
version = "0.115.2"
|
version = "0.115.2"
|
||||||
@ -193,6 +321,17 @@ files = [
|
|||||||
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
||||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
|
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "2.22"
|
||||||
|
description = "C parser in Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
|
||||||
|
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.9.2"
|
version = "2.9.2"
|
||||||
@ -317,6 +456,23 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyjwt"
|
||||||
|
version = "2.9.0"
|
||||||
|
description = "JSON Web Token implementation in Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"},
|
||||||
|
{file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
crypto = ["cryptography (>=3.4.0)"]
|
||||||
|
dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||||
|
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||||
|
tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyright"
|
name = "pyright"
|
||||||
version = "1.1.384"
|
version = "1.1.384"
|
||||||
@ -379,4 +535,4 @@ files = [
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.12"
|
python-versions = "^3.12"
|
||||||
content-hash = "eb858921311d767fbc6e8b45ef3fbb86a299b1a389408fafc7facd3a07eaa866"
|
content-hash = "4d0ace334226402b2f825c6d1d480056b7588d4f79ccbf2297ec01c720b74108"
|
||||||
|
@ -7,6 +7,9 @@ authors = []
|
|||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.12"
|
python = "^3.12"
|
||||||
fastapi = "^0.115.2"
|
fastapi = "^0.115.2"
|
||||||
|
pydantic = "^2.9.2"
|
||||||
|
pyjwt = "^2.9.0"
|
||||||
|
cryptography = "^43.0.1"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^24.1.1"
|
black = "^24.1.1"
|
||||||
|
22
scripts/get_jwks.bash
Executable file
22
scripts/get_jwks.bash
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Key the JWKS
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
local gateway_address
|
||||||
|
gateway_address=$(tf output -raw gateway_address)
|
||||||
|
curl "https://$gateway_address/.well-known/jwks.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
function tf() {
|
||||||
|
terraform -chdir="$DIR/../terraform" "${@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
main "${@}"
|
24
scripts/hit_protected_endpoint.bash
Executable file
24
scripts/hit_protected_endpoint.bash
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Hit an endpoint that requires a valid JWT.
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
local jwt
|
||||||
|
jwt=$(cd "$DIR"/../api_server && poetry run python -m api_server.local_generate_long_lived_token)
|
||||||
|
local gateway_address
|
||||||
|
gateway_address=$(tf output -raw gateway_address)
|
||||||
|
curl -H "Authorization: Bearer $jwt" "https://$gateway_address/some_protected_endpoint"
|
||||||
|
}
|
||||||
|
|
||||||
|
function tf() {
|
||||||
|
terraform -chdir="$DIR/../terraform" "${@}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
main "${@}"
|
@ -60,3 +60,22 @@ provider "registry.terraform.io/hashicorp/random" {
|
|||||||
"zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af",
|
"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 {
|
ports {
|
||||||
container_port = 8080
|
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"], ]
|
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" {
|
resource "google_api_gateway_api" "api" {
|
||||||
provider = google-beta
|
provider = google-beta
|
||||||
project = google_project.project.project_id
|
project = google_project.project.project_id
|
||||||
@ -13,31 +16,8 @@ resource "google_api_gateway_api_config" "api_config" {
|
|||||||
|
|
||||||
openapi_documents {
|
openapi_documents {
|
||||||
document {
|
document {
|
||||||
path = "spec.yaml"
|
path = "spec.yaml"
|
||||||
contents = base64encode(<<-EOF
|
contents = base64encode(templatefile("openapi_spec.yaml", { backend_url = google_cloud_run_v2_service.api_server.uri, client_id = random_uuid.jwt_client_id.result }))
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,9 +27,20 @@ resource "google_api_gateway_gateway" "gateway" {
|
|||||||
project = google_project.project.project_id
|
project = google_project.project.project_id
|
||||||
api_config = google_api_gateway_api_config.api_config.id
|
api_config = google_api_gateway_api_config.api_config.id
|
||||||
gateway_id = "gateway-to-the-api"
|
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" {
|
output "gateway_address" {
|
||||||
value = google_api_gateway_gateway.gateway.default_hostname
|
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" {
|
resource "google_project_service" "service" {
|
||||||
project = google_project.project.project_id
|
project = google_project.project.project_id
|
||||||
for_each = toset(["run", "artifactregistry", "apigateway"])
|
for_each = toset(["run", "artifactregistry", "apigateway", "secretmanager"])
|
||||||
service = "${each.key}.googleapis.com"
|
service = "${each.key}.googleapis.com"
|
||||||
disable_dependent_services = true
|
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}"
|
Loading…
Reference in New Issue
Block a user