Sensible Daten mit Secret Manager und Batch schützen

In diesem Dokument wird beschrieben, wie Sie sensible Daten, die Sie für einen Batchjob angeben möchten, mit Secret Manager-Secrets schützen.

Secret Manager-Secrets schützen sensible Daten durch Verschlüsselung. In einem Batchjob können Sie ein oder mehrere vorhandene Secrets angeben, um die darin enthaltenen vertraulichen Daten sicher zu übergeben. Sie können sie dann für Folgendes verwenden:

Hinweise

  1. Wenn Sie Batch noch nicht verwendet haben, lesen Sie den Hilfeartikel Batch-Dateien erstellen und ausführen und aktivieren Sie Batch, indem Sie die Voraussetzungen für Projekte und Nutzer erfüllen.
  2. Erstellen Sie ein Secret oder identifizieren Sie ein Secret für die vertraulichen Daten, die Sie für einen Job sicher angeben möchten.
  3. Bitten Sie Ihren Administrator, Ihnen die folgenden IAM-Rollen zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Erstellen eines Jobs benötigen:

    Weitere Informationen zum Zuweisen von Rollen finden Sie unter Zugriff auf Projekte, Ordner und Organisationen verwalten.

    Sie können die erforderlichen Berechtigungen auch über benutzerdefinierte Rollen oder andere vordefinierte Rollen erhalten.

  4. Damit das Dienstkonto des Jobs die erforderlichen Berechtigungen zum Zugriff auf Secrets hat, bitten Sie Ihren Administrator, dem Dienstkonto des Jobs die IAM-Rolle Secret Manager Secret Accessor (roles/secretmanager.secretAccessor) für das Secret zu erteilen.

Sensible Daten sicher an benutzerdefinierte Umgebungsvariablen übergeben

Wenn Sie vertrauliche Daten sicher von Secret Manager-Secrets an benutzerdefinierte Umgebungsvariablen übergeben möchten, müssen Sie jede Umgebungsvariable im Unterfeld Secret-Variablen (secretVariables) für eine Umgebung definieren und für jeden Wert ein Secret angeben. Wenn Sie ein Secret in einem Job angeben, muss es als Pfad zu einer Secret-Version formatiert werden: projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION.

Sie können einen Job erstellen, der geheime Variablen definiert, mit der gcloud CLI, der Batch API, Java, Node.js oder Python. Im folgenden Beispiel wird beschrieben, wie ein Job erstellt wird, in dem eine Secret-Variable für die Umgebung aller ausführbaren Dateien (environment-Unterfeld von taskSpec) definiert und verwendet wird.

gcloud

  1. Erstellen Sie eine JSON-Datei, in der die Konfigurationsdetails des Jobs angegeben sind, und fügen Sie das Unterfeld secretVariables für eine oder mehrere Umgebungen hinzu.

    Wenn Sie beispielsweise einen einfachen Script-Job erstellen möchten, der für alle ausführbaren Dateien eine geheime Variable in der Umgebung verwendet, erstellen Sie eine JSON-Datei mit folgendem Inhalt:

    {
      "taskGroups": [
        {
          "taskSpec": {
            "runnables": [
              {
                "script": {
                  "text": "echo This is the secret: ${SECRET_VARIABLE_NAME}"
                }
              }
            ],
            "environment": {
              "secretVariables": {
                "{SECRET_VARIABLE_NAME}": "projects/PROJECT_ID/secrets/SECRET_NAME/versions/VERSION"
              }
            }
          }
        }
      ],
      "logsPolicy": {
        "destination": "CLOUD_LOGGING"
      }
    }
    

    Ersetzen Sie Folgendes:

    • SECRET_VARIABLE_NAME: der Name der geheimen Variablen. Gemäß Konvention werden Namen von Umgebungsvariablen großgeschrieben.

      Geben Sie diesen Variablennamen in den ausführbaren Dateien dieses Jobs an, um sicher auf die sensiblen Daten aus dem Secret Manager-Secret der Variablen zuzugreifen. Auf die Secret-Variable können alle ausführbaren Dateien zugreifen, die sich in derselben Umgebung befinden, in der Sie die Secret-Variable definieren.

    • PROJECT_ID: die Projekt-ID Ihres Projekts.

    • SECRET_NAME: Der Name eines vorhandenen Secret Manager-Secrets.

    • VERSION: die Version des angegebenen Secrets, die die Daten enthält, die Sie an den Job übergeben möchten. Dies kann die Versionsnummer oder latest sein.

  2. Verwenden Sie den Befehl gcloud batch jobs submit, um den Job zu erstellen und auszuführen:

    gcloud batch jobs submit JOB_NAME \
      --location LOCATION \
      --config JSON_CONFIGURATION_FILE
    

    Ersetzen Sie Folgendes:

    • JOB_NAME: Der Name des Jobs.

    • LOCATION: den Standort der Stelle.

    • JSON_CONFIGURATION_FILE: der Pfad zu einer JSON-Datei mit den Konfigurationsdetails des Jobs.

API

Stellen Sie eine POST-Anfrage an die jobs.create-Methode, in der das Unterfeld secretVariables für eine oder mehrere Umgebungen angegeben ist.

Wenn Sie beispielsweise einen einfachen Script-Job erstellen möchten, der für alle ausführbaren Dateien eine geheime Variable in der Umgebung verwendet, stellen Sie folgende Anfrage:

POST https://batch.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/jobs?job_id=JOB_NAME
{
  "taskGroups": [
    {
      "taskSpec": {
        "runnables": [
          {
            "script": {
              "text": "echo This is the secret: ${SECRET_VARIABLE_NAME}"
            }
          }
        ],
        "environment": {
          "secretVariables": {
            "{SECRET_VARIABLE_NAME}": "projects/PROJECT_ID/secrets/SECRET_NAME/versions/VERSION"
          }
        }
      }
    }
  ],
  "logsPolicy": {
    "destination": "CLOUD_LOGGING"
  }
}

Ersetzen Sie Folgendes:

  • PROJECT_ID: die Projekt-ID Ihres Projekts.

  • LOCATION: den Standort der Stelle.

  • JOB_NAME: Der Name des Jobs.

  • SECRET_VARIABLE_NAME: der Name der geheimen Variablen. Gemäß Konvention werden Namen von Umgebungsvariablen großgeschrieben.

    Geben Sie diesen Variablennamen in den ausführbaren Dateien dieses Jobs an, um sicher auf die sensiblen Daten aus dem Secret Manager-Secret der Variablen zuzugreifen. Auf die Secret-Variable können alle ausführbaren Dateien zugreifen, die sich in derselben Umgebung befinden, in der Sie die Secret-Variable definieren.

  • SECRET_NAME: Der Name eines vorhandenen Secret Manager-Secrets.

  • VERSION: die Version des angegebenen Secrets, die die Daten enthält, die Sie an den Job übergeben möchten. Dies kann die Versionsnummer oder latest sein.

Java


import com.google.cloud.batch.v1.BatchServiceClient;
import com.google.cloud.batch.v1.CreateJobRequest;
import com.google.cloud.batch.v1.Environment;
import com.google.cloud.batch.v1.Job;
import com.google.cloud.batch.v1.LogsPolicy;
import com.google.cloud.batch.v1.LogsPolicy.Destination;
import com.google.cloud.batch.v1.Runnable;
import com.google.cloud.batch.v1.Runnable.Script;
import com.google.cloud.batch.v1.TaskGroup;
import com.google.cloud.batch.v1.TaskSpec;
import com.google.protobuf.Duration;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateBatchUsingSecretManager {

  public static void main(String[] args)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Google Cloud project you want to use.
    String projectId = "YOUR_PROJECT_ID";
    // Name of the region you want to use to run the job. Regions that are
    // available for Batch are listed on: https://cloud.google.com/batch/docs/get-started#locations
    String region = "europe-central2";
    // The name of the job that will be created.
    // It needs to be unique for each project and region pair.
    String jobName = "JOB_NAME";
    // The name of the secret variable.
    // This variable name is specified in this job's runnables
    // and is accessible to all of the runnables that are in the same environment.
    String secretVariableName = "VARIABLE_NAME";
    // The name of an existing Secret Manager secret.
    String secretName = "SECRET_NAME";
    // The version of the specified secret that contains the data you want to pass to the job.
    // This can be the version number or latest.
    String version = "VERSION";

    createBatchUsingSecretManager(projectId, region,
            jobName, secretVariableName, secretName, version);
  }

  // Create a basic script job to securely pass sensitive data.
  // The data is obtained from Secret Manager secrets
  // and set as custom environment variables in the job.
  public static Job createBatchUsingSecretManager(String projectId, String region,
                                                  String jobName, String secretVariableName,
                                                  String secretName, String version)
      throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (BatchServiceClient batchServiceClient = BatchServiceClient.create()) {
      // Define what will be done as part of the job.
      Runnable runnable =
          Runnable.newBuilder()
              .setScript(
                  Script.newBuilder()
                      .setText(
                          String.format("echo This is the secret: ${%s}.", secretVariableName))
                      // You can also run a script from a file. Just remember, that needs to be a
                      // script that's already on the VM that will be running the job.
                      // Using setText() and setPath() is mutually exclusive.
                      // .setPath("/tmp/test.sh")
                      .build())
              .build();

      // Construct the resource path to the secret's version.
      String secretValue = String
              .format("projects/%s/secrets/%s/versions/%s", projectId, secretName, version);

      // Set the secret as an environment variable.
      Environment.Builder environmentVariable = Environment.newBuilder()
          .putSecretVariables(secretVariableName, secretValue);

      TaskSpec task = TaskSpec.newBuilder()
          // Jobs can be divided into tasks. In this case, we have only one task.
          .addRunnables(runnable)
          .setEnvironment(environmentVariable)
          .setMaxRetryCount(2)
          .setMaxRunDuration(Duration.newBuilder().setSeconds(3600).build())
          .build();

      // Tasks are grouped inside a job using TaskGroups.
      // Currently, it's possible to have only one task group.
      TaskGroup taskGroup = TaskGroup.newBuilder()
          .setTaskSpec(task)
          .build();

      Job job =
          Job.newBuilder()
              .addTaskGroups(taskGroup)
              .putLabels("env", "testing")
              .putLabels("type", "script")
              // We use Cloud Logging as it's an out of the box available option.
              .setLogsPolicy(
                  LogsPolicy.newBuilder().setDestination(Destination.CLOUD_LOGGING))
              .build();

      CreateJobRequest createJobRequest =
          CreateJobRequest.newBuilder()
              // The job's parent is the region in which the job will run.
              .setParent(String.format("projects/%s/locations/%s", projectId, region))
              .setJob(job)
              .setJobId(jobName)
              .build();

      Job result =
          batchServiceClient
              .createJobCallable()
              .futureCall(createJobRequest)
              .get(5, TimeUnit.MINUTES);

      System.out.printf("Successfully created the job: %s", result.getName());

      return result;
    }
  }
}

Node.js

// Imports the Batch library
const batchLib = require('@google-cloud/batch');
const batch = batchLib.protos.google.cloud.batch.v1;

// Instantiates a client
const batchClient = new batchLib.v1.BatchServiceClient();

/**
 * TODO(developer): Update these variables before running the sample.
 */
// Project ID or project number of the Google Cloud project you want to use.
const projectId = await batchClient.getProjectId();
// Name of the region you want to use to run the job. Regions that are
// available for Batch are listed on: https://cloud.google.com/batch/docs/get-started#locations
const region = 'europe-central2';
// The name of the job that will be created.
// It needs to be unique for each project and region pair.
const jobName = 'batch-job-secret-manager';
// The name of the secret variable.
// This variable name is specified in this job's runnables
// and is accessible to all of the runnables that are in the same environment.
const secretVariableName = 'secretVariableName';
// The name of an existing Secret Manager secret.
const secretName = 'secretName';
// The version of the specified secret that contains the data you want to pass to the job.
// This can be the version number or latest.
const version = 'version';

// Define what will be done as part of the job.
const runnable = new batch.Runnable({
  script: new batch.Runnable.Script({
    commands: ['-c', `echo This is the secret: ${secretVariableName}`],
  }),
});

// Construct the resource path to the secret's version.
const secretValue = `projects/${projectId}/secrets/${secretName}/versions/${version}`;

// Set the secret as an environment variable.
const environment = new batch.Environment();
environment.secretVariables[secretVariableName] = secretValue;

const task = new batch.TaskSpec({
  runnables: [runnable],
  environment,
  maxRetryCount: 2,
  maxRunDuration: {seconds: 3600},
});

// Tasks are grouped inside a job using TaskGroups.
const group = new batch.TaskGroup({
  taskCount: 3,
  taskSpec: task,
});

const job = new batch.Job({
  name: jobName,
  taskGroups: [group],
  labels: {env: 'testing', type: 'script'},
  // We use Cloud Logging as it's an option available out of the box
  logsPolicy: new batch.LogsPolicy({
    destination: batch.LogsPolicy.Destination.CLOUD_LOGGING,
  }),
});

// The job's parent is the project and region in which the job will run
const parent = `projects/${projectId}/locations/${region}`;

async function callCreateUsingSecretManager() {
  // Construct request
  const request = {
    parent,
    jobId: jobName,
    job,
  };

  // Run request
  const [response] = await batchClient.createJob(request);
  console.log(JSON.stringify(response));
}

await callCreateUsingSecretManager();

Python

from typing import Dict, Optional

from google.cloud import batch_v1


def create_with_secret_manager(
    project_id: str,
    region: str,
    job_name: str,
    secrets: Dict[str, str],
    service_account_email: Optional[str] = None,
) -> batch_v1.Job:
    """
    This method shows how to create a sample Batch Job that will run
    a simple command on Cloud Compute instances with passing secrets from secret manager.
    Note: Job's service account should have the permissions to access secrets.
        - Secret Manager Secret Accessor (roles/secretmanager.secretAccessor) IAM role.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        region: name of the region you want to use to run the job. Regions that are
            available for Batch are listed on: https://cloud.google.com/batch/docs/get-started#locations
        job_name: the name of the job that will be created.
            It needs to be unique for each project and region pair.
        secrets: secrets, which should be passed to the job. Environment variables should be capitalized
        by convention https://google.github.io/styleguide/shellguide.html#constants-and-environment-variable-names
            The format should look like:
                - {'SECRET_NAME': 'projects/{project_id}/secrets/{SECRET_NAME}/versions/{version}'}
            version can be set to 'latest'.
        service_account_email (optional): custom service account email

    Returns:
        A job object representing the job created.
    """
    client = batch_v1.BatchServiceClient()

    # Define what will be done as part of the job.
    task = batch_v1.TaskSpec()
    runnable = batch_v1.Runnable()
    runnable.script = batch_v1.Runnable.Script()
    runnable.script.text = (
        "echo Hello world! from task ${BATCH_TASK_INDEX}."
        + f" ${next(iter(secrets.keys()))} is the value of the secret."
    )
    task.runnables = [runnable]
    task.max_retry_count = 2
    task.max_run_duration = "3600s"

    envable = batch_v1.Environment()
    envable.secret_variables = secrets
    task.environment = envable

    # Tasks are grouped inside a job using TaskGroups.
    # Currently, it's possible to have only one task group.
    group = batch_v1.TaskGroup()
    group.task_count = 4
    group.task_spec = task

    # Policies are used to define on what kind of virtual machines the tasks will run on.
    # Read more about local disks here: https://cloud.google.com/compute/docs/disks/persistent-disks
    policy = batch_v1.AllocationPolicy.InstancePolicy()
    policy.machine_type = "e2-standard-4"
    instances = batch_v1.AllocationPolicy.InstancePolicyOrTemplate()
    instances.policy = policy
    allocation_policy = batch_v1.AllocationPolicy()
    allocation_policy.instances = [instances]

    service_account = batch_v1.ServiceAccount()
    service_account.email = service_account_email
    allocation_policy.service_account = service_account

    job = batch_v1.Job()
    job.task_groups = [group]
    job.allocation_policy = allocation_policy
    job.labels = {"env": "testing", "type": "script"}
    # We use Cloud Logging as it's an out of the box available option
    job.logs_policy = batch_v1.LogsPolicy()
    job.logs_policy.destination = batch_v1.LogsPolicy.Destination.CLOUD_LOGGING

    create_request = batch_v1.CreateJobRequest()
    create_request.job = job
    create_request.job_id = job_name
    # The job's parent is the region in which the job will run
    create_request.parent = f"projects/{project_id}/locations/{region}"

    return client.create_job(create_request)

Sicherer Zugriff auf Container-Images, für die Docker-Registry-Anmeldedaten erforderlich sind

Wenn Sie ein Container-Image aus einer privaten Docker-Registry verwenden möchten, müssen Sie für ein ausführbares Programm Anmeldedaten angeben, mit denen es auf diese Docker-Registry zugreifen kann. Insbesondere müssen Sie für jeden Container, der mit dem Feld Image-URI (imageUri) ausgeführt werden kann, das auf ein Image aus einer privaten Docker-Registry festgelegt ist, alle für den Zugriff auf diese Docker-Registry erforderlichen Anmeldedaten angeben. Verwenden Sie dazu die Felder Nutzername (username) und Passwort (password).

Sie können alle vertraulichen Anmeldedaten für eine Docker-Registrierung schützen, indem Sie vorhandene Secrets angeben, die die Informationen enthalten, anstatt diese Felder direkt zu definieren. Wenn Sie ein Secret in einem Job angeben, muss es als Pfad zu einer Secret-Version formatiert werden: projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION.

Mit der gcloud CLI oder der Batch API können Sie einen Job erstellen, der Container-Images aus einer privaten Docker-Registry verwendet. Im folgenden Beispiel wird erläutert, wie Sie einen Job erstellen, der ein Container-Image aus einer privaten Docker-Registry verwendet. Dazu geben Sie den Nutzernamen direkt und das Passwort als Secret an.

gcloud

  1. Erstellen Sie eine JSON-Datei mit den Konfigurationsdetails des Jobs. Geben Sie für alle ausführbaren Container, die Images aus einer privaten Docker-Registry verwenden, in den Feldern username und password alle Anmeldedaten an, die für den Zugriff erforderlich sind.

    Wenn Sie beispielsweise einen einfachen Containerauftrag erstellen möchten, der ein Image aus einer privaten Docker-Registry angibt, erstellen Sie eine JSON-Datei mit folgendem Inhalt:

    {
      "taskGroups": [
        {
          "taskSpec": {
            "runnables": [
              {
                "container": {
                  "imageUri": "PRIVATE_IMAGE_URI",
                  "commands": [
                    "-c",
                    "echo This runnable uses a private image."
                  ],
                  "username": "USERNAME",
                  "password": "PASSWORD"
                }
              }
            ],
          }
        }
      ],
      "logsPolicy": {
        "destination": "CLOUD_LOGGING"
      }
    }
    

    Ersetzen Sie Folgendes:

    • PRIVATE_IMAGE_URI: Der Image-URI für ein Container-Image aus einer privaten Docker-Registry. Wenn für dieses Image weitere Containereinstellungen erforderlich sind, müssen Sie auch diese angeben.

    • USERNAME: Der Nutzername für die private Docker-Registry, der als Secret oder direkt angegeben werden kann.

    • PASSWORD: das Passwort für die private Docker-Registry, das als Secret (empfohlen) oder direkt angegeben werden kann.

      Wenn Sie das Passwort beispielsweise als Secret angeben möchten, legen Sie PASSWORD auf Folgendes fest:

      projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION
      

      Ersetzen Sie Folgendes:

      • PROJECT_ID: die Projekt-ID Ihres Projekts.

      • SECRET_NAME: Der Name eines vorhandenen Secret Manager-Secrets.

      • VERSION: die Version des angegebenen Secrets, die die Daten enthält, die Sie an den Job übergeben möchten. Dies kann die Versionsnummer oder latest sein.

  2. Verwenden Sie den Befehl gcloud batch jobs submit, um den Job zu erstellen und auszuführen:

    gcloud batch jobs submit JOB_NAME \
      --location LOCATION \
      --config JSON_CONFIGURATION_FILE
    

    Ersetzen Sie Folgendes:

    • JOB_NAME: Der Name des Jobs.

    • LOCATION: den Standort der Stelle.

    • JSON_CONFIGURATION_FILE: der Pfad zu einer JSON-Datei mit den Konfigurationsdetails des Jobs.

API

Stellen Sie eine POST-Anfrage an die Methode jobs.create. Geben Sie für alle ausführbaren Container, die Images aus einer privaten Docker-Registry verwenden, in den Feldern username und password alle Anmeldedaten an, die für den Zugriff erforderlich sind.

Wenn Sie beispielsweise einen einfachen Containerjob erstellen möchten, für den ein Image aus einer privaten Docker-Registry angegeben wird, stellen Sie folgende Anfrage:

POST https://batch.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/jobs?job_id=JOB_NAME
{
  "taskGroups": [
    {
      "taskSpec": {
        "runnables": [
          {
            "container": {
              "imageUri": "PRIVATE_IMAGE_URI",
                "commands": [
                  "-c",
                  "echo This runnable uses a private image."
                ],
                "username": "USERNAME",
                "password": "PASSWORD"
            }
          }
        ],
      }
    }
  ],
  "logsPolicy": {
    "destination": "CLOUD_LOGGING"
  }
}

Ersetzen Sie Folgendes:

  • PROJECT_ID: die Projekt-ID Ihres Projekts.

  • LOCATION: den Standort der Stelle.

  • JOB_NAME: Der Name des Jobs.

  • PRIVATE_IMAGE_URI: Der Image-URI für ein Container-Image aus einer privaten Docker-Registry. Wenn für dieses Image weitere Containereinstellungen erforderlich sind, müssen Sie auch diese angeben.

  • USERNAME: Der Nutzername für die private Docker-Registry, der als Secret oder direkt angegeben werden kann.

  • PASSWORD: das Passwort für die private Docker-Registry, das als Secret (empfohlen) oder direkt angegeben werden kann.

    Wenn Sie das Passwort beispielsweise als Secret angeben möchten, legen Sie PASSWORD auf Folgendes fest:

    projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION
    

    Ersetzen Sie Folgendes:

    • PROJECT_ID: die Projekt-ID Ihres Projekts.

    • SECRET_NAME: Der Name eines vorhandenen Secret Manager-Secrets.

    • VERSION: die Version des angegebenen Secrets, die die Daten enthält, die Sie an den Job übergeben möchten. Dies kann die Versionsnummer oder latest sein.

Nächste Schritte