0

I am facing these issues, When I try to make my Cloud Run Instances to allow only authenticated invocations (Requires Authentication)

I have multiple GCP Projects and many Cloud Run Instances in each project, Sometimes they have to communicate like this Project A's Cloud Run Instance (CR-A1) has to communicate with Project B's Cloud Run Instance (CR-B1) and also sometimes, Cloud Run Instances present in Project A/B has to communicates other Cloud Run Instances present in the same Project like CR-A1 communicates CR-A2

For Cross Project Communication:

I have created a Service Account (SA-Project A) and used it in Security Service Account for CR-A1 instance while deploying, this Service Account has all required IAM permissions such as Editor, Service Account Token Creator, Sql Admin. And the same Service Account (SA-Project A) has been added in Project B with **Cloud Run Invoker ** IAM Permission

Now when I try to make a Rest call from CR-A1 Instance to CR-B1 . I am getting "Client Not Authorized 401 Error"

I even have created Service Account keys and generated its access token from using default credentials of SA-Project A, and used that access token as Bearer token sent it Http Headers, Still same error,

Can anyone help here Please,

Question may be little complex of typical, Please take some time to understand.

Note : All Cloud Run Instances Requires Authentication.

Thank you

Requirement

Successful Authentication among Cross Project CR API Invocations and also CR API Invocations in Same Project.

Kindly note that, all Cloud Run(CR) Instances requires authentication

  • Could you show the code that you use to call your service account key? What is the language of your Cloud Run? – Alberto Vitoriano Apr 20 '23 at 13:49
  • @AlbertoVitoriano I have used Java code, Here is code block used to get access token using service account keys
    ` public String getAccessToken() throws IOException { GoogleCredentials credentials = GoogleCredentials.fromStream(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream("service-account-key.json"))); credentials = credentials.createScoped("https://www.googleapis.com/auth/cloud-platform"); credentials.refreshIfExpired(); return credentials.getAccessToken().getTokenValue(); }`
    – Nagender Varma Apr 20 '23 at 13:58
  • Arf, that's the trick!! You use an Access Token, you have to use an Identity Token. Easy no? (joke...) – guillaume blaquiere Apr 20 '23 at 14:12
  • There are two types of authorization tokens used in Google Cloud. OAuth Access Tokens and OIDC Identity Tokens. Cloud Run requires OIDC Identity Tokens. https://cloud.google.com/run/docs/authenticating/overview Java example code: https://cloud.google.com/run/docs/authenticating/service-to-service#run-service-to-service-example-java – John Hanley Apr 20 '23 at 16:22
  • @guillaumeblaquiere Thank you for the inputs, Now I am able to authenticate with Cloud Run Instances – Nagender Varma Apr 21 '23 at 06:13
  • @JohnHanley Thank you for the inputs, Now I am able to authenticate with Cloud Run Instances – Nagender Varma Apr 21 '23 at 06:13

2 Answers2

2

Posting this as a community wiki so that others can benefit from it.


As mentioned by @John Hanley: "There are two types of authorization tokens used in Google Cloud. OAuth Access Tokens and OIDC Identity Tokens. Cloud Run requires OIDC Identity Tokens.

Authentication overview Java Example: Authenticating service-to-service"

Chanpols
  • 1,184
  • 1
  • 3
  • 13
1

Cloud Run Service to Service

  1. Create a service account in 1st GCP Project with IAM permission as Service Account Token Creator, and use this Service Account in Cloud Run Instance 1.
  2. Add the Service Account(Step 1) in 2nd GCP Project IAM, with Cloud Run Invoker.
  3. Create Service Account Keys for Service Account in 1st GCP Project(Step 1),
  4. Store these Servicee Account Keys in GCP Secret Manager for security, and use these keys whenever you want to generate OIDC Token.
  5. Now we can use OIDC Tokens in HttpHeaders with Authorization as "Bearer "

These OIDC token will authenticate your Rest Call from Cloud Run Instance 1 of 1st GCP Project to Cloud Run Instance 2 of 2nd GCP Project.

Check below code to generate OIDC token in Java Code

public String getOIDCTOken(){
     Credentials creds= GoogleCredentials.fromStream(new ByteArrayInputStream(getSAKeysFromSecretManager(<ProjectId>, <secretName>, <version>).getBytes()));

     IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
                .setIdTokenProvider((IdTokenProvider) credentials)
                .setTargetAudience(https://<instance-name>-ID-region.run.app) // Cloud Run Instance 2nd Url 
                .build();
      AccessToken token = idTokenCredentials.refreshAccessToken();
      return token.getTokenValue();
} 

//To get secrets from Secret Manager 
public String getSAKeysFromSecretManager(projectId, secretName, version){
       AccessSecretVersionResponse response;
       try(SecretManagerServiceClient client = create()){
       SecretVersionName secretVersionName= SecretVersionName.of(projectId,secretName,version);
       response = client.accessSecretVersion(secretVersionName)
       }
      return response.getPayload().getData().toStringUtf8();
}