189 lines
9.8 KiB
Markdown
189 lines
9.8 KiB
Markdown
# Transfer files from a Linux filesystem with Storage Transfer Service and X.509 WIF
|
|
|
|
This guide tests whether the Storage Transfer Service agent works with Workload Identity Federation (WIF) instead of a service account key. The agent copies files from a Linux filesystem to the WIF test bucket. Both the agent and the `gcloud` commands that create and run the transfer job authenticate as the service account `sa-test`, which they impersonate with the X.509 client certificate. The filesystem mounted at `/mnt/ext-storage` stands in for an external storage appliance.
|
|
|
|
## Prerequisites
|
|
|
|
The guide uses two hosts.
|
|
|
|
Admin workstation, for sections 2, 5 and 6:
|
|
|
|
- The repository with `env.sh`, where the pool, provider, service account and bucket were created as described in the main `README.md`.
|
|
- `gcloud` authenticated as an administrator of the target project in the `default` configuration.
|
|
- The `wif-test` gcloud configuration from a successful run of `test_wif.sh`.
|
|
|
|
Agent host, for sections 3 and 4:
|
|
|
|
- Linux on AMD64 with a container runtime, Python 3, and the external storage mounted at `/mnt/ext-storage`.
|
|
- A copy of this repository, a `git clone` or an archive unpacked as described in the section "Copy the repository to a server" of the main `README.md`, with `env.sh` created as described in the Configuration section of the main `README.md`. The commands run from its directory.
|
|
- With the Vault CA, the client certificate renewed in `/etc/sts-agent/`, as described in section 4 of `docs/vault-approle.md`. With the OpenSSL CA, the certificate is installed in section 3.
|
|
|
|
The names come from `env.sh`.
|
|
|
|
## 1. Identities
|
|
|
|
A transfer from a filesystem is agent based. It involves three identities:
|
|
|
|
| Identity | Principal | Purpose | Roles |
|
|
|---|---|---|---|
|
|
| Job creator | `sa-test` through the `wif-test` configuration | Creates and runs transfer jobs | `roles/storagetransfer.user`, `roles/iam.roleViewer` |
|
|
| Transfer agent | `sa-test` through tokens of the IMDS emulator, which authenticates with Application Default Credentials (ADC) and `/etc/sts-agent/cred.json` | Reads the files and writes the objects | `roles/storagetransfer.transferAgent`, `roles/storage.objectAdmin` on the bucket |
|
|
| Service agent | `project-PROJECT_NUMBER@storage-transfer-service.iam.gserviceaccount.com` | Manages the Pub/Sub topics of the pool, checks the transferred objects and writes the transfer logs | `roles/storagetransfer.serviceAgent`, `roles/storage.legacyBucketReader`, `roles/storage.objectViewer` and `roles/storage.objectCreator` on the bucket |
|
|
|
|
The service agent is managed by Google and exists once per project. It cannot be replaced with a user-managed service account in agent based transfers.
|
|
|
|
## 2. Configure the project
|
|
|
|
Role: **Administrator**
|
|
|
|
`make_sts.sh` performs the following steps with the `default` gcloud configuration:
|
|
|
|
1. Enables the Storage Transfer API.
|
|
2. Creates the Storage Transfer service agent and shows its email.
|
|
3. Grants the service agent its project and bucket roles.
|
|
4. Grants the service account the job creator and the transfer agent roles.
|
|
5. Creates the agent pool.
|
|
|
|
```bash
|
|
bash make_sts.sh
|
|
```
|
|
|
|
## 3. Prepare the agent credentials
|
|
|
|
Role: **Server administrator**
|
|
|
|
### Install the client certificate
|
|
|
|
The agent reads the client certificate and key, which authenticate the service account it uses, from its credential directory `/etc/sts-agent/`, regardless of the CA that issued them. With the Vault CA, `vault-cert-renew@wif.timer` keeps them there and this step is skipped.
|
|
|
|
With the OpenSSL CA, `make_certs.sh` created `client_cert.pem` and `client_key.pem` in the repository directory on the admin workstation. Copy them to the agent host, replacing `agent-host` with its name:
|
|
|
|
```bash
|
|
scp client_cert.pem client_key.pem agent-host:
|
|
```
|
|
|
|
Install them on the agent host and delete the copies:
|
|
|
|
```bash
|
|
sudo install -d -m 0750 /etc/sts-agent
|
|
sudo install -m 0644 ~/client_cert.pem /etc/sts-agent/client_cert.pem
|
|
sudo install -m 0600 ~/client_key.pem /etc/sts-agent/client_key.pem
|
|
rm ~/client_cert.pem ~/client_key.pem
|
|
```
|
|
|
|
### Create the credentials configuration
|
|
|
|
`make_sts_agent_creds.py` runs on the agent host. It checks that the client certificate and key exist in `/etc/sts-agent`, sets the mode of the directory to 0750, and creates the following files next to them:
|
|
|
|
- `cred.json`, the credentials configuration for the X.509 provider and the impersonation of the service account. The agent finds it through the `GOOGLE_APPLICATION_CREDENTIALS` environment variable. It refers to the default certificate configuration, which the agent finds through the `GOOGLE_API_CERTIFICATE_CONFIG` environment variable.
|
|
- `certificate_config.json`, with the paths of the client certificate and key.
|
|
|
|
```bash
|
|
source ./env.sh
|
|
sudo ./make_sts_agent_creds.py \
|
|
--project-number="${PROJECT_NUMBER}" \
|
|
--pool="${POOL_ID}" \
|
|
--provider="${PROVIDER_ID}" \
|
|
--service-account="${SA_EMAIL}"
|
|
```
|
|
|
|
The option `--output` (default `/etc/sts-agent`) changes the credential directory.
|
|
|
|
The agent reads the certificate and key from the mounted directory, so certificates renewed there by `vault-cert-renew@wif.timer` are used without changes to the configuration.
|
|
|
|
## 4. Start the transfer agent
|
|
|
|
Role: **Server administrator**
|
|
|
|
The agent cannot use the X.509 credentials itself. Its launcher is a statically linked binary that cannot load the `cryptography` package, which certificate-based authentication requires, and the `--creds-file` option accepts only a service account key or user credentials. The agent therefore gets its tokens from the IMDS emulator, a Compute Engine metadata server emulator in a second container. The emulator authenticates with ADC and the X.509 credentials in `/etc/sts-agent`, and serves the access tokens of `sa-test` on the metadata token endpoint. Without `GOOGLE_APPLICATION_CREDENTIALS`, ADC in the agent falls back to the metadata server, which `GCE_METADATA_HOST` and `GCE_METADATA_IP` point to the emulator.
|
|
|
|
The containers run with the following settings:
|
|
|
|
| Container | Setting | Value |
|
|
|---|---|---|
|
|
| `imds-emulator` | Image | built from `sts-agent/Dockerfile` |
|
|
| | Mount | `/etc/sts-agent`, read only |
|
|
| | Environment | `GOOGLE_APPLICATION_CREDENTIALS=/etc/sts-agent/cred.json` |
|
|
| | Environment | `GOOGLE_API_CERTIFICATE_CONFIG=/etc/sts-agent/certificate_config.json` |
|
|
| | Environment | `PROJECT_ID`, `PROJECT_NUMBER` |
|
|
| `sts-agent` | Image | `gcr.io/cloud-ingest/tsop-agent:latest` |
|
|
| | Mount | `/mnt/ext-storage`, read only |
|
|
| | Environment | `GCE_METADATA_HOST=imds-emulator`, `GCE_METADATA_IP=imds-emulator` |
|
|
| | Locked memory limit | `64000000` bytes |
|
|
| | Arguments | `--project-id=${PROJECT_ID} --hostname=$(hostname) --agent-pool=${STS_AGENT_POOL}` |
|
|
|
|
The emulator publishes no port; only the containers of the Compose project reach it. The agent container must not set `GOOGLE_API_CERTIFICATE_CONFIG`, because the metadata token code of the agent parses the certificate it points to with `cryptography`.
|
|
|
|
`sts-agent/compose.yaml` holds these settings for Docker Compose. Compose substitutes `PROJECT_ID`, `PROJECT_NUMBER`, `STS_AGENT_POOL` and `HOSTNAME` from `sts-agent/.env`. Create the file with the values of `env.sh` and the host name printed by `hostname`:
|
|
|
|
`sts-agent/.env`:
|
|
|
|
```bash
|
|
PROJECT_ID=my-project
|
|
PROJECT_NUMBER=123456789012
|
|
STS_AGENT_POOL=my-agents
|
|
HOSTNAME=agent-host
|
|
```
|
|
|
|
Build the emulator and start both containers:
|
|
|
|
```bash
|
|
cd sts-agent
|
|
docker compose build
|
|
docker compose up -d
|
|
```
|
|
|
|
The emulator logs one line per request with the path and the status, never the token:
|
|
|
|
```bash
|
|
docker compose logs imds-emulator
|
|
```
|
|
|
|
Requests for paths that the emulator does not serve are logged with the status 404.
|
|
|
|
`imds_test.py` in the emulator container tests the emulator. It checks the metadata endpoints and the rejection of requests without the `Metadata-Flavor` header or with `X-Forwarded-For`. It then authenticates with the Compute Engine credentials of `google-auth` against the emulator, the same way as the agent, and checks the token with the Google token information endpoint. With `--bucket`, it also lists the objects of the bucket with the token:
|
|
|
|
```bash
|
|
source ../env.sh
|
|
docker compose exec imds-emulator /venv/bin/python3 /app/imds_test.py --bucket "${BUCKET}"
|
|
```
|
|
|
|
It prints `PASS` or `FAIL` for each check and exits with status 1 when a check fails.
|
|
|
|
The source directory is mounted at the same path as on the host, because the transfer job refers to it by that path.
|
|
|
|
The connected agents of the pool are listed on the Agent pools page of the Google Cloud console. An agent appears there only after it has authenticated.
|
|
|
|
## 5. Run the transfer
|
|
|
|
Role: **Job creator**
|
|
|
|
The name of a transfer job with a POSIX filesystem source or destination must start with `OPI`, so `STS_JOB_NAME` in `env.sh` has this prefix.
|
|
|
|
`test_sts.sh` runs on the admin workstation and performs the following steps:
|
|
|
|
1. Switches to the `wif-test` gcloud configuration.
|
|
2. Shows the agent pool.
|
|
3. Creates the transfer job from `/mnt/ext-storage` to the `ext-storage/` folder of the bucket, and waits until its first run finishes.
|
|
4. Lists the operations of the job and the transferred objects.
|
|
5. Switches back to the original gcloud configuration.
|
|
6. Lists the audit log of the service account operations, including the Storage Transfer calls.
|
|
|
|
```bash
|
|
bash test_sts.sh
|
|
```
|
|
|
|
## 6. Check the result
|
|
|
|
The test passes when all of the following are true:
|
|
|
|
1. The agent is listed as connected on the Agent pools page.
|
|
2. The operation of the job has the status `SUCCESS`, and the files of `/mnt/ext-storage` are listed under `gs://${BUCKET}/ext-storage/`.
|
|
3. The audit log lists the object writes with `sa-test` as `EMAIL` and the client certificate subject `test-client` as `DELEGATED_BY`.
|
|
|
|
The job copies only files that are new or changed since the previous run. To run it again later:
|
|
|
|
```bash
|
|
gcloud transfer jobs run "${STS_JOB_NAME}" --no-async --configuration=wif-test
|
|
```
|