Skip to content

Commit 65177a5

Browse files
authored
[Cloud Run] Auth Snippet (GoogleCloudPlatform#2557)
Fixes #<issue_number_goes_here> > It's a good idea to open an issue first for discussion. - [ ] Tests pass - [ ] Appropriate changes to README are included in PR - [ ] API's need to be enabled to test (tell us) - [ ] Environment Variables need to be set (ask us to set them)
1 parent cbc9e8e commit 65177a5

File tree

5 files changed

+241
-43
lines changed

5 files changed

+241
-43
lines changed

.kokoro/tests/build_cloud_run.sh

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,57 +14,60 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17-
set -eo pipefail
17+
JIB=$(grep -o '<artifactId>jib-maven-plugin</artifactId>' pom.xml)
18+
if [ -n "$JIB" ]; then
19+
set -eo pipefail
1820

19-
# Register post-test cleanup.
20-
# Only needed if deploy completed.
21-
function cleanup {
22-
set -x
23-
gcloud container images delete "${CONTAINER_IMAGE}" --quiet --no-user-output-enabled || true
24-
gcloud run services delete ${SERVICE_NAME} \
25-
--platform=managed \
26-
--region="${REGION:-us-central1}" \
27-
--quiet --no-user-output-enabled
28-
mvn clean
29-
}
30-
trap cleanup EXIT
21+
# Register post-test cleanup.
22+
# Only needed if deploy completed.
23+
function cleanup {
24+
set -x
25+
gcloud container images delete "${CONTAINER_IMAGE}" --quiet --no-user-output-enabled || true
26+
gcloud run services delete ${SERVICE_NAME} \
27+
--platform=managed \
28+
--region="${REGION:-us-central1}" \
29+
--quiet --no-user-output-enabled
30+
mvn clean
31+
}
32+
trap cleanup EXIT
3133

32-
requireEnv() {
33-
test "${!1}" || (echo "Environment Variable '$1' not found" && exit 1)
34-
}
35-
requireEnv SAMPLE_NAME
34+
requireEnv() {
35+
test "${!1}" || (echo "Environment Variable '$1' not found" && exit 1)
36+
}
37+
requireEnv SAMPLE_NAME
3638

37-
# Version is in the format <PR#>-<GIT COMMIT SHA>.
38-
# Ensures PR-based triggers of the same branch don't collide if Kokoro attempts
39-
# to run them concurrently.
40-
export SAMPLE_VERSION="${KOKORO_GIT_COMMIT:-latest}"
41-
# Builds not triggered by a PR will fall back to the commit hash then "latest".
42-
SUFFIX=${KOKORO_GITHUB_PULL_REQUEST_NUMBER:-${SAMPLE_VERSION:0:12}}
43-
export SERVICE_NAME="${SAMPLE_NAME}-${SUFFIX}"
44-
export CONTAINER_IMAGE="gcr.io/${GOOGLE_CLOUD_PROJECT}/run-${SAMPLE_NAME}:${SAMPLE_VERSION}"
45-
export SPECIAL_BASE_IMAGE="gcr.io/${GOOGLE_CLOUD_PROJECT}/imagemagick"
46-
BASE_IMAGE_SAMPLES=("image-processing" "system-packages")
39+
# Version is in the format <PR#>-<GIT COMMIT SHA>.
40+
# Ensures PR-based triggers of the same branch don't collide if Kokoro attempts
41+
# to run them concurrently.
42+
export SAMPLE_VERSION="${KOKORO_GIT_COMMIT:-latest}"
43+
# Builds not triggered by a PR will fall back to the commit hash then "latest".
44+
SUFFIX=${KOKORO_GITHUB_PULL_REQUEST_NUMBER:-${SAMPLE_VERSION:0:12}}
45+
export SERVICE_NAME="${SAMPLE_NAME}-${SUFFIX}"
46+
export CONTAINER_IMAGE="gcr.io/${GOOGLE_CLOUD_PROJECT}/run-${SAMPLE_NAME}:${SAMPLE_VERSION}"
47+
export SPECIAL_BASE_IMAGE="gcr.io/${GOOGLE_CLOUD_PROJECT}/imagemagick"
48+
BASE_IMAGE_SAMPLES=("image-processing" "system-packages")
4749

48-
# Build the service
49-
set -x
50+
# Build the service
51+
set -x
5052

51-
mvn jib:build -Dimage="${CONTAINER_IMAGE}" \
52-
`if [[ "${BASE_IMAGE_SAMPLES[@]}" =~ "${SAMPLE_NAME}" ]]; then echo "-Djib.from.image=${SPECIAL_BASE_IMAGE}"; fi`
53+
mvn jib:build -Dimage="${CONTAINER_IMAGE}" \
54+
`if [[ "${BASE_IMAGE_SAMPLES[@]}" =~ "${SAMPLE_NAME}" ]]; then echo "-Djib.from.image=${SPECIAL_BASE_IMAGE}"; fi`
5355

54-
gcloud run deploy "${SERVICE_NAME}" \
55-
--image="${CONTAINER_IMAGE}" \
56-
--region="${REGION:-us-central1}" \
57-
--platform=managed \
58-
--quiet --no-user-output-enabled \
59-
`if [ $SAMPLE_NAME = "image-processing" ]; then echo "--memory 512M"; fi`
56+
gcloud run deploy "${SERVICE_NAME}" \
57+
--image="${CONTAINER_IMAGE}" \
58+
--region="${REGION:-us-central1}" \
59+
--platform=managed \
60+
--quiet --no-user-output-enabled \
61+
`if [ $SAMPLE_NAME = "image-processing" ]; then echo "--memory 512M"; fi`
6062

6163

62-
set +x
64+
set +x
6365

64-
echo
65-
echo '---'
66-
echo
66+
echo
67+
echo '---'
68+
echo
6769

70+
# Do not use exec to preserve trap behavior.
71+
"$@"
6872

69-
# Do not use exec to preserve trap behavior.
70-
"$@"
73+
fi

run/authentication/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Authenticating service-to-service
2+
3+
This sample shows how to make an authenticated request by retrieving a JSON Web Tokens (JWT) from the [metadata server](https://cloud.google.com/run/docs/securing/service-identity#identity_tokens).
4+
5+
For more details on how to work with this sample read [Authenticating service-to-service](https://cloud.google.com/run/docs/authenticating/service-to-service).
6+
7+
**Note** You cannot query an instance's metadata from another instance or directly from your local computer. For testing purposes, this sample uses the environment variable, `"GOOGLE_CLOUD_PROJECT"`, to determine local or instance environment. To run tests locally, make sure environment variable, `"GOOGLE_CLOUD_PROJECT"`, is not set.

run/authentication/pom.xml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright 2019 Google LLC
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
-->
14+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
15+
<modelVersion>4.0.0</modelVersion>
16+
<groupId>com.example.cloudrun</groupId>
17+
<artifactId>authentication</artifactId>
18+
<packaging>jar</packaging>
19+
<version>1.0-SNAPSHOT</version>
20+
21+
<!--
22+
The parent pom defines common style checks and testing strategies for our samples.
23+
Removing or replacing it should not affect the execution of the samples in anyway.
24+
-->
25+
<parent>
26+
<groupId>com.google.cloud.samples</groupId>
27+
<artifactId>shared-configuration</artifactId>
28+
<version>1.0.13</version>
29+
</parent>
30+
31+
<properties>
32+
<maven.compiler.target>1.8</maven.compiler.target>
33+
<maven.compiler.source>1.8</maven.compiler.source>
34+
</properties>
35+
36+
<dependencies>
37+
<dependency>
38+
<groupId>com.squareup.okhttp3</groupId>
39+
<artifactId>okhttp</artifactId>
40+
<version>4.4.1</version>
41+
</dependency>
42+
43+
<dependency>
44+
<groupId>junit</groupId>
45+
<artifactId>junit</artifactId>
46+
<version>4.13</version>
47+
<scope>test</scope>
48+
</dependency>
49+
50+
</dependencies>
51+
</project>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.cloudrun;
18+
19+
// [START run_service_to_service_auth]
20+
import java.io.IOException;
21+
import java.util.concurrent.TimeUnit;
22+
import okhttp3.OkHttpClient;
23+
import okhttp3.Request;
24+
import okhttp3.Response;
25+
26+
public class Authentication {
27+
28+
// Instantiate OkHttpClient
29+
private static final OkHttpClient ok =
30+
new OkHttpClient.Builder()
31+
.readTimeout(10, TimeUnit.SECONDS)
32+
.writeTimeout(10, TimeUnit.SECONDS)
33+
.build();
34+
35+
// makeGetRequest makes a GET request to the specified Cloud Run endpoint,
36+
// serviceUrl (must be a complete URL), by authenticating with the Id token
37+
// obtained from the Metadata API.
38+
public static Response makeGetRequest(String serviceUrl) throws IOException {
39+
Request.Builder serviceRequest = new Request.Builder().url(serviceUrl);
40+
41+
// Set up metadata server request
42+
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
43+
String tokenUrl =
44+
String.format(
45+
"http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=%s",
46+
serviceUrl);
47+
Request tokenRequest =
48+
new Request.Builder().url(tokenUrl).addHeader("Metadata-Flavor", "Google").get().build();
49+
// Fetch the token
50+
try (Response tokenResponse = ok.newCall(tokenRequest).execute()) {
51+
String token = tokenResponse.body().string();
52+
// Provide the token in the request to the receiving service
53+
serviceRequest.addHeader("Authorization", "Bearer " + token);
54+
System.out.println("Id token query succeeded.");
55+
} catch (IOException e) {
56+
System.out.println("Id token query failed: " + e);
57+
}
58+
59+
return ok.newCall(serviceRequest.get().build()).execute();
60+
}
61+
}
62+
// [END run_service_to_service_auth]
63+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.cloudrun;
18+
19+
import static org.hamcrest.MatcherAssert.assertThat;
20+
import static org.hamcrest.core.StringContains.containsString;
21+
22+
import java.io.ByteArrayOutputStream;
23+
import java.io.IOException;
24+
import java.io.PrintStream;
25+
import org.junit.After;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
29+
public class AuthenticationTest {
30+
private ByteArrayOutputStream bout;
31+
private PrintStream out;
32+
String expectedResp;
33+
34+
@Before
35+
public void setUp() {
36+
bout = new ByteArrayOutputStream();
37+
out = new PrintStream(bout);
38+
System.setOut(out);
39+
40+
// This test uses the existence of env var "GOOGLE_CLOUD_PROJECT"
41+
// to determine local vs GCP environment only for testing purposes.
42+
if (System.getenv("GOOGLE_CLOUD_PROJECT") != null) {
43+
expectedResp = "Id token query succeeded";
44+
System.out.println("Running on GCP...");
45+
} else {
46+
expectedResp = "Id token query failed";
47+
System.out.println("Running locally...");
48+
}
49+
}
50+
51+
@After
52+
public void tearDown() {
53+
System.setOut(null);
54+
}
55+
56+
@Test
57+
public void canMakeGetRequest() throws IOException {
58+
String url = "http://example.com/";
59+
Authentication.makeGetRequest(url);
60+
String got = bout.toString();
61+
assertThat(got, containsString(expectedResp));
62+
}
63+
64+
@Test
65+
public void failsMakeGetRequestWithoutProtocol() throws IOException {
66+
String url = "example.com/";
67+
try {
68+
Authentication.makeGetRequest(url);
69+
} catch (IllegalArgumentException e) {
70+
assertThat(e.getMessage(), containsString("Expected URL scheme 'http' or 'https'"));
71+
}
72+
}
73+
}
74+

0 commit comments

Comments
 (0)