Chapter 3. Forward to Google Cloud


You can forward logs to Google Cloud Logging by using service account keys or Workload Identity Federation.

Forward logs to Google Cloud Logging by using a Google service account key for authentication.

Note

For improved security, consider using Workload Identity Federation instead of long-lived service account keys. See "Forwarding logs to Google Cloud with Workload Identity Federation".

Important

Forwarding logs to GCP is not supported on Red Hat OpenShift on AWS.

Prerequisites

  • Ensure that you installed the Red Hat OpenShift Logging Operator.

Procedure

  1. Create a secret using your Google service account key.

    $ oc -n openshift-logging create secret generic gcp-secret --from-file google-application-credentials.json=<your_service_account_key_file.json>
  2. Create a ClusterLogForwarder Custom Resource YAML using the template below:

    apiVersion: observability.openshift.io/v1
    kind: ClusterLogForwarder
    metadata:
      name: <log_forwarder_name>
      namespace: openshift-logging
    spec:
      serviceAccount:
        name: <service_account_name>
      outputs:
        - name: gcp-1
          type: googleCloudLogging
          googleCloudLogging:
            authentication:
              credentials:
                secretName: gcp-secret
                key: google-application-credentials.json
            id:
              type : project
              value: <your_project_id>
            logId : app-gcp
      pipelines:
        - name: test-app
          inputRefs:
            - application
          outputRefs:
            - gcp-1
    serviceAccount.name
    Specify the name of your service account.
    value
    Set a project, folder, organization, or billingAccount field and its corresponding value, depending on where you want to store your logs in the GCP resource hierarchy.
    logId
    Set the value to add to the logName field of the log entry. The value can be a combination of static and dynamic values consisting of field paths followed by ||, followed by another field path or a static value. You must encase a dynamic value in single curly brackets {} and follow it with a static fallback value separated with ||. Static values can only contain alphanumeric characters along with dashes, underscores, dots and forward slashes.
    inputRefs
    Specify the names of inputs defined in the input.name field for this pipeline. You can also use the built-in values application, infrastructure, audit.

When you forward logs to Google Cloud Logging, the log collector transforms OpenShift log records into the LogEntry format defined by the Cloud Logging API. Understanding this transformation helps you configure log queries and alerting in the Google Cloud Console.

The log collector sends logs to Google Cloud Logging by using the LogEntry data type. Each OpenShift log record becomes a single LogEntry with the following required and optional fields:

logName (required)
Resource name in the format projects/[PROJECT_ID]/logs/[LOG_ID]. You can also use organizations/, folders/, or billingAccounts/ prefixes depending on where you want to store logs in the Google Cloud resource hierarchy.
Payload
You must specify exactly one payload type: jsonPayload for structured JSON objects, textPayload for plain text strings, or protoPayload for protocol buffer messages. The log collector typically uses jsonPayload to preserve the complete OpenShift log record structure.
resource (optional)
Monitored resource metadata with a type and labels. For Kubernetes logs, common types include k8s_cluster, k8s_node, k8s_pod, and k8s_container.
timestamp (optional)
Entry timestamp in RFC3339 format with nanosecond accuracy. The collector converts the log record’s @timestamp field to this format.
severity (optional)
Log severity level. The collector maps the OpenShift log record’s level field to Google Cloud Logging severity values: DEFAULT, DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, or EMERGENCY.
labels (optional)
User-defined key-value pairs for metadata. You can extract fields from the log record to populate these labels.

The following table shows common field mappings from OpenShift log records to Google Cloud LogEntry:

OpenShift fieldLogEntry fieldTransformation

Complete log record

jsonPayload

Entire log record preserved as structured JSON

@timestamp

timestamp

Converted to RFC3339 with nanosecond accuracy

level

severity

Mapped to Google Cloud severity level (for example, "error" ERROR)

kubernetes.cluster_name

resource.labels.cluster_name

Extracted to resource labels

kubernetes.namespace_name

resource.labels.namespace_name

Extracted to resource labels

kubernetes.pod_name

resource.labels.pod_name

Extracted to resource labels

kubernetes.container_name

resource.labels.container_name

Extracted to resource labels

{
  "kubernetes": {
    "namespace_name": "my-app",
    "pod_name": "web-1",
    "container_name": "nginx",
    "cluster_name": "prod-cluster"
  },
  "message": "Error connecting to database",
  "level": "error",
  "@timestamp": "2024-01-15T10:30:00Z"
}

The log collector transforms this into a Google Cloud LogEntry:

{
  "logName": "projects/my-project/logs/openshift-logs",
  "resource": {
    "type": "k8s_container",
    "labels": {
      "cluster_name": "prod-cluster",
      "namespace_name": "my-app",
      "pod_name": "web-1",
      "container_name": "nginx"
    }
  },
  "timestamp": "2024-01-15T10:30:00.000000000Z",
  "severity": "ERROR",
  "labels": {
    "log_source": "openshift",
    "environment": "production"
  },
  "jsonPayload": {
    "message": "Error connecting to database",
    "kubernetes": {
      "namespace_name": "my-app",
      "pod_name": "web-1",
      "container_name": "nginx"
    },
    "level": "error"
  }
}

The resource.type field determines which labels Google Cloud expects. For the k8s_container type, you must provide cluster_name, namespace_name, pod_name, and container_name labels. Template syntax in your ClusterLogForwarder configuration extracts these values from the log record’s Kubernetes metadata fields.

Google Cloud Logging requires service account credentials with the logging.logEntries.create permission. The Logs Writer role provides this permission at the organization, folder, project, or billing account level.

Forward logs to Google Cloud Logging by using Workload Identity Federation (WIF) for authentication. WIF provides short-lived credentials instead of long-lived service account keys. This approach improves security by eliminating the need to manage and rotate service account key files.

Important

Forwarding logs to GCP with Workload Identity Federation is only supported on Red Hat OpenShift on GCP.

Prerequisites

  • You have installed the Red Hat OpenShift Logging Operator.
  • Your Red Hat OpenShift Logging cluster is installed on GCP in manual credentials mode with Workload Identity Federation (WIF) enabled.
  • You have access to the ccoctl utility that was used during cluster installation.
  • You have gcloud CLI installed and configured for your GCP project.
  • You have the GCP project number, not the project ID. To get this value, run: gcloud projects describe <PROJECT_ID> --format="value(projectNumber)"
Important

Workload Identity Federation must be enabled during cluster installation. You cannot retrofit WIF onto an existing cluster that was not installed with WIF support. If your cluster was not installed with WIF, use service account keys instead.

Procedure

  1. Set environment variables for your GCP project and cluster configuration:

    $ export PROJECT_ID="<your_gcp_project_id>"
    $ export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
    $ export LOGGING_NS="openshift-logging"
    $ export SA_NAME="logcollector"
    $ export SECRET_NAME="gcp-wif-secret"
    $ export POOL_ID="<your_cluster_name>"
    $ export PROVIDER_ID="<your_cluster_name>"
    $ export GCP_SA_NAME="openshift-logging-writer"
    $ export SERVICE_ACCOUNT_EMAIL="${GCP_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
    POOL_ID
    The workload identity pool ID created during cluster installation. This typically matches your cluster name.
    PROVIDER_ID

    The workload identity provider ID created during cluster installation. This typically matches the pool ID.

    Warning

    The audience field in the CredentialsRequest must use your GCP project number, not your project ID. Using the project ID instead of the project number causes HTTP 403 Forbidden errors.

  2. Create a CredentialsRequest custom resource YAML file named credrequest.yaml:

    apiVersion: cloudcredential.openshift.io/v1
    kind: CredentialsRequest
    metadata:
      name: gcp-wif-credrequest
      namespace: openshift-cloud-credential-operator
    spec:
      providerSpec:
        apiVersion: cloudcredential.openshift.io/v1
        kind: GCPProviderSpec
        predefinedRoles:
          - roles/logging.logWriter
        skipServiceCheck: true
        audience: "//iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${POOL_ID}/providers/${PROVIDER_ID}"
        serviceAccountEmail: ${SERVICE_ACCOUNT_EMAIL}
      cloudTokenPath: /var/run/ocp-collector/serviceaccount
      secretRef:
        name: ${SECRET_NAME}
        namespace: ${LOGGING_NS}
      serviceAccountNames:
        - ${SA_NAME}
    metadata.namespace
    The standard namespace for CredentialsRequest resources.
    spec.providerSpec.predefinedRoles
    The GCP IAM role granting permissions to write log entries to Google Cloud Logging.
    spec.providerSpec.audience
    The WIF audience. This must use the project number, not the project ID.
    spec.providerSpec.serviceAccountEmail
    The email address of the GCP service account that ccoctl will create or use.
    spec.cloudTokenPath
    The path where the OpenShift service account token is mounted in the collector pod.
    spec.secretRef.namespace
    The namespace where the secret will be created. This should match the namespace where you will deploy the ClusterLogForwarder.
    spec.serviceAccountNames
    The name of the OpenShift service account that the collector pods will use.
  3. Use the ccoctl utility to create the GCP service account and IAM bindings:

    $ mkdir -p credreqs
    $ cp credrequest.yaml credreqs/
    $ ccoctl gcp create-all \
      --name="${POOL_ID}" \
      --project="${PROJECT_ID}" \
      --region="us-east1" \
      --credentials-requests-dir=credreqs \
      --output-dir=output

    This command creates:

    • A GCP service account with the specified email address
    • IAM policy bindings granting the roles/logging.logWriter role
    • A workload identity binding between the OpenShift service account and the GCP service account
    • An OpenShift secret manifest containing the external account credentials
  4. Apply the generated secret manifest:

    $ oc apply -f output/manifests/${LOGGING_NS}-${SECRET_NAME}-credentials.yaml
  5. Update the secret to fix the cloudTokenPath for the collector:

    Important

    The ccoctl utility does not respect the cloudTokenPath setting in the CredentialsRequest. You must manually update the generated secret to use the correct token path for the logging collector.

    $ oc get secret ${SECRET_NAME} -n ${LOGGING_NS} -o jsonpath='{.data.service_account\.json}' | base64 -d > /tmp/creds.json
    $ jq '.credential_source.file = "/var/run/ocp-collector/serviceaccount/token"' /tmp/creds.json > /tmp/external_account.json
    $ oc delete secret ${SECRET_NAME} -n ${LOGGING_NS}
    $ oc create secret generic ${SECRET_NAME} -n ${LOGGING_NS} \
      --from-file=external_account.json=/tmp/external_account.json
  6. Verify the secret was updated correctly:

    $ oc get secret ${SECRET_NAME} -n ${LOGGING_NS} -o jsonpath='{.data.external_account\.json}' | base64 -d | jq .credential_source

    The output should show:

    {
      "file": "/var/run/ocp-collector/serviceaccount/token"
    }
  7. Create a ClusterLogForwarder custom resource that uses WIF authentication:

    apiVersion: observability.openshift.io/v1
    kind: ClusterLogForwarder
    metadata:
      name: <log_forwarder_name>
      namespace: openshift-logging
    spec:
      serviceAccount:
        name: logcollector
      outputs:
        - name: gcp-wif
          type: googleCloudLogging
          googleCloudLogging:
            authentication:
              credentials:
                secretName: gcp-wif-secret
                key: external_account.json
              token:
                from: serviceAccount
            id:
              type: project
              value: <your_project_id>
            logId: openshift-logs
      pipelines:
        - name: send-to-gcp
          inputRefs:
            - application
            - infrastructure
            - audit
          outputRefs:
            - gcp-wif
    metadata.namespace
    The namespace where the ClusterLogForwarder is deployed. This should match the namespace specified in the CredentialsRequest secret reference.
    spec.serviceAccount.name
    The OpenShift service account name. This must match the serviceAccountNames value in the CredentialsRequest.
    spec.outputs.googleCloudLogging.authentication.credentials.key
    The secret key containing the external account configuration file. Note that this is external_account.json, not service_account.json, because you manually recreated the secret in the previous step.
    spec.outputs.googleCloudLogging.authentication.token.from
    Specifies that the bearer token comes from the service account. The collector uses the service account token as the subject token for WIF token exchange with GCP.

Verification

  1. Check the log collector pods to verify that they are running:

    $ oc get pods -n openshift-logging -l app.kubernetes.io/component=collector
  2. Review the collector pod logs to confirm successful authentication and log forwarding:

    $ oc logs -n openshift-logging <collector_pod_name> | grep -i gcp
  3. In the GCP console, navigate to Logging > Logs Explorer and verify that logs from your OpenShift cluster are appearing.
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat Documentation

Legal Notice

Theme

© 2026 Red Hat
Back to top