8000 Sample for Cloud Run service-to-service authentication (#4414) · JoseSoler/python-docs-samples@912f195 · GitHub
[go: up one dir, main page]

Skip to content

Commit 912f195

Browse files
authored
Sample for Cloud Run service-to-service authentication (GoogleCloudPlatform#4414)
* New authentication sample
1 parent 36c7b80 commit 912f195

File tree

6 files changed

+233
-0
lines changed

6 files changed

+233
-0
lines changed

auth/service-to-service/auth.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright 2020 Google, LLC.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Demonstrates how to send authenticated service-to-service requests, eg
17+
for Cloud Run or Cloud Functions"""
18+
19+
# [START google_auth_idtoken_serverless]
20+
# [START functions_bearer_token]
21+
# [START run_service_to_service_auth]
22+
import urllib
23+
24+
import google.auth.transport.requests
25+
import google.oauth2.id_token
26+
27+
28+
def make_authorized_get_request(service_url):
29+
"""
30+
make_authorized_get_request makes a GET request to the specified HTTP endpoint
31+
in service_url (must be a complete URL) by authenticating with the
32+
ID token obtained from the google-auth client library.
33+
"""
34+
35+
req = urllib.request.Request(service_url)
36+
37+
auth_req = google.auth.transport.requests.Request()
38+
id_token = google.oauth2.id_token.fetch_id_token(auth_req, service_url)
39+
40+
req.add_header("Authorization", f"Bearer {id_token}")
41+
response = urllib.request.urlopen(req)
42+
43+
return response.read()
44+
# [END run_service_to_service_auth]
45+
# [END functions_bearer_token]
46+
# [END google_auth_idtoken_serverless]

auth/service-to-service/auth_test.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Copyright 2020 Google, LLC.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
< 8000 span class=pl-c># This test deploys a secure application running on Cloud Run
16+
# to test that the authentication sample works properly.
17+
18+
import os
19+
import subprocess
20+
from urllib import request
21+
import uuid
22+
23+
import pytest
24+
25+
26+
@pytest.fixture()
27+
def services():
28+
# Unique suffix to create distinct service names
29+
suffix = uuid.uuid4().hex
30+
project = os.environ['GOOGLE_CLOUD_PROJECT']
31+
32+
# Deploy hello-world Cloud Run Service from
33+
# https://github.com/GoogleCloudPlatform/cloud-run-hello
34+
subprocess.run(
35+
[
36+
"gcloud", "run", "deploy", f"helloworld-{suffix}",
37+
"--project", project,
38+
"--image=gcr.io/cloudrun/hello",
39+
"--platform=managed",
40+
"--region=us-central1",
41+
"--no-allow-unauthenticated",
42+
"--quiet",
43+
], check=True
44+
)
45+
46+
# Get the URL for the hello-world service
47+
service_url = subprocess.run(
48+
[
49+
"gcloud", "run", "services", "describe", f"helloworld-{suffix}",
50+
"--project", project,
51+
"--platform=managed",
52+
"--region=us-central1",
53+
"--format=value(status.url)",
54+
],
55+
stdout=subprocess.PIPE,
56+
check=True
57+
).stdout.strip()
58+
59+
# Deploy function for service-to-service authentication
60+
subprocess.run(
61+
[
62+
"gcloud", "functions", "deploy", f"helloworld-{suffix}",
63+
"--project", project,
64+
"--runtime=python38",
65+
"--region=us-central1",
66+
"--trigger-http",
67+
"--no-allow-unauthenticated",
68+
"--entry-point=get_authorized",
69+
f"--set-env-vars=URL={service_url.decode()}"
70+
],
71+
check=True
72+
)
73+
74+
function_url = (
75+
f"https://us-central1-{project}.cloudfunctions.net/helloworld-{suffix}")
76+
77+
token = subprocess.run(
78+
["gcloud", "auth", "print-identity-token"], stdout=subprocess.PIPE,
79+
check=True
80+
).stdout.strip()
81+
82+
yield function_url, token
83+
84+
subprocess.run(
85+
[
86+
"gcloud", "run", "services", "delete", f"helloworld-{suffix}",
87+
"--project", project,
88+
"--platform=managed",
89+
"--region=us-central1",
90+
"--quiet",
91+
],
92+
check=True
93+
)
94+
95+
subprocess.run(
96+
[
97+
"gcloud", "functions", "delete", f"helloworld-{suffix}",
98+
"--project", project,
99+
"--region=us-central1",
100+
"--quiet",
101+
],
102+
check=True
103+
)
104+
105+
106+
def test_auth(services):
107+
url = services[0]
108+
token = services[1].decode()
109+
110+
req = request.Request(url, headers={"Authorization": f"Bearer {token}"})
111+
112+
response = request.urlopen(req)
113+
assert response.status == 200
114+
assert "Hello World" in response.read().decode()

auth/service-to-service/main.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright 2020 Google, LLC.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# This file holds a function for testing service-to-service authentication
16+
17+
import os
18+
19+
import auth
20+
21+
22+
def get_authorized(request):
23+
# Makes an authenticated request to URL set in environment variables
24+
try:
25+
url = os.environ.get("URL")
26+
response = auth.make_authorized_get_request(url)
27+
return response
28+
29+
except Exception as e:
30+
print(e)
31+
return str(e)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2020 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Default TEST_CONFIG_OVERRIDE for python repos.
16+
17+
# You can copy this file into your directory, then it will be inported from
18+
# the noxfile.py.
19+
20+
# The source of truth:
21+
# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/noxfile_config.py
22+
23+
TEST_CONFIG_OVERRIDE = {
24+
# You can opt out from the test for specific Python versions.
25+
26+
# We only run the cloud run tests in py38 session.
27+
'ignored_versions': ["2.7", "3.6", "3.7"],
28+
29+
# An envvar key for determining the project id to use. Change it
30+
# to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
31+
# build specific Cloud project. You can also use your own string
32+
# to use your own Cloud project.
33+
'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT',
34+
# 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
35+
36+
# A dictionary you want to inject into your test. Don't put any
37+
# secrets here. These values will override predefined values.
38+
'envs': {},
39+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest==6.0.1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
google-auth==1.20.0
2+
requests==2.24.0

0 commit comments

Comments
 (0)
0