更新 SFTP 用户的存储分区

本文档介绍了如何更新 Cloud FTP 用户的 Cloud Storage 存储桶,包括用户可以访问哪些存储桶以及用户拥有哪些权限。

从总体上讲,更新用户存储桶的步骤如下:

  1. 更新用户服务帐号的 IAM 角色。
  2. 将用户的目录映射到更新后的存储桶。

准备工作

所需角色

如需获得更新 SFTP 用户所需的权限,请让您的管理员为您授予项目的FTP Admin (roles/ftp.admin) IAM 角色。如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限。

此预定义角色包含更新 SFTP 用户所需的 ftp.users.update 权限。

您也可以使用自定义角色或其他预定义角色来获取此权限。

更新用户服务帐号的 IAM 角色

如果您更改了用户可以访问的存储桶,或者更改了用户对现有目录映射拥有的权限,则必须使用相关的 IAM 角色更新用户的服务帐号。请执行以下操作:

  1. 获取用户服务帐号的电子邮件地址。如需了解相关步骤,请参阅 获取有关用户的详细信息。

  2. 如果您向目录映射添加了新存储桶或增加了对现有存储桶的访问权限,请执行以下操作:

    1. 如果您还没有存储桶的 Storage Bucket Viewer (roles/storage.bucketViewer) 角色,请向自己授予该角色:

      gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
          --member="user:ADMINISTRATOR_EMAIL" \
          --role="roles/storage.bucketViewer"

      替换以下内容:

      • ADMINISTRATOR_EMAIL:创建 SFTP 用户的主账号的电子邮件地址。如果您(而不是应用)要创建 用户,则此值是您用于访问的电子邮件 地址 Google Cloud。

      • BUCKET_NAME:存储桶的名称。

    2. 如果您还没有存储桶的 Storage Object Viewer (roles/storage.objectViewer) 角色,请向自己授予该角色:

      gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
          --member="user:ADMINISTRATOR_EMAIL" \
          --role="roles/storage.objectViewer"
    3. 向用户的服务帐号授予访问存储桶所需的 IAM 角色:

      gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
        --member="serviceAccount:SERVICE_ACCOUNT" \
        --role="ROLE_TO_GRANT"

      替换以下内容:

      • SERVICE_ACCOUNT:用户服务帐号的电子邮件地址。
      • ROLE_TO_GRANT:要授予的 IAM 角色。指定以下角色之一:

        • 如需只读访问权限,请使用 roles/storage.objectViewer 角色。
        • 如需读写访问权限,请使用 roles/storage.objectAdmin 角色。
    4. 针对用户需要访问的每个存储桶重复上述步骤。

  3. 如果您从目录映射中移除了存储桶或减少了对现有存储桶的访问权限,请撤消用户服务帐号的访问权限:

    gcloud storage buckets remove-iam-policy-binding gs://BUCKET_NAME \
      --member="serviceAccount:SERVICE_ACCOUNT" \
      --role="ROLE_TO_REVOKE"

    将 ROLE_TO_REVOKE 替换为您要撤消的 IAM 角色。

    针对用户不应再有权访问的每个存储桶和 IAM 角色重复此步骤。

更新用户的存储桶

gcloud

如需更新 SFTP 用户的存储桶,请运行 gcloud alpha storage ftp users update 命令。

在使用以下任何命令数据之前, 请进行以下替换:

  • USERNAME:SFTP 用户的用户名。
  • LOCATION_ID:服务器 的位置,例如 us-west1。
  • SERVER_ID:服务器 ID。
  • BUCKET_NAME:向 SFTP 用户授予访问权限的存储桶的名称,例如 example-bucket。省略 gs://。
  • (可选)BUCKET_PREFIX:存储桶中要设置为此目录映射的 根目录的文件夹的路径。 如果您省略 bucket_prefix 属性,则 Cloud FTP 会使用存储桶根目录。
  • DIRECTORY:向 SFTP 用户显示的逻辑着陆目录路径。例如,/home/uploads。

    如果您映射了多个存储桶或文件夹,请为每个 映射提供唯一的目录路径。

    不支持嵌套的逻辑目录。如果您为某个目录提供了多个映射, 请以扁平结构(而不是嵌套结构)提供目录。例如,使用 /dir1 和 /dir2,而不是 /dir1 和 /dir1/dir2。

  • SFTP_PERMISSION:目录的访问权限级别。如需只读访问权限,请将此 值设置为 READ_ONLY。如需读写访问权限,请将此值设置为 READ_WRITE。

如需向用户授予对多个存储桶的访问权限,请多次提供 --storage-directory-mapping 标志,并为每个存储桶提供一个目录映射。

执行以下命令:

Linux、macOS 或 Cloud Shell

gcloud alpha storage ftp users update USERNAME --location=LOCATION_ID \
    --server=SERVER_ID \
    --storage-directory-mapping=bucket=BUCKET_NAME,bucket_prefix=BUCKET_PREFIX,directory=DIRECTORY,permission=SFTP_PERMISSION

Windows (PowerShell)

gcloud alpha storage ftp users update USERNAME --location=LOCATION_ID `
    --server=SERVER_ID `
    --storage-directory-mapping=bucket=BUCKET_NAME,bucket_prefix=BUCKET_PREFIX,directory=DIRECTORY,permission=SFTP_PERMISSION

Windows (cmd.exe)

gcloud alpha storage ftp users update USERNAME --location=LOCATION_ID ^
    --server=SERVER_ID ^
    --storage-directory-mapping=bucket=BUCKET_NAME,bucket_prefix=BUCKET_PREFIX,directory=DIRECTORY,permission=SFTP_PERMISSION
更新用户需要几秒钟的时间。

如果用户有活跃的 SFTP 连接, 则可能需要断开连接,然后重新连接,更新后的存储桶 设置才会生效。

REST

如需更新 SFTP 用户的存储桶,请使用 servers.users.patch 方法。 在 updateMask 查询参数中,提供 storageDirectoryMappings 字段。

在使用任何请求数据之前, 请进行以下替换:

  • PROJECT_ID:服务器的 Google Cloud 项目 ID。
  • LOCATION_ID:服务器的位置,例如 us-west1。
  • SERVER_ID:服务器 ID。
  • USERNAME:SFTP 用户的用户名。
  • BUCKET_NAME:向 SFTP 用户授予访问权限的存储桶的名称,例如 example-bucket。省略 gs://。
  • (可选)BUCKET_PREFIX:存储桶中要设置为此目录映射的 根目录的文件夹的路径。 如果您省略此值,则 Cloud FTP 会使用存储桶 根目录。
  • DIRECTORY:向 SFTP 用户显示的逻辑着陆目录路径。例如,/home/uploads。如果您省略此值,则 Cloud FTP 会将 着陆目录设置为 /。

    如果您映射了多个存储桶或文件夹,请为每个 映射提供唯一的目录路径。

    不支持嵌套的逻辑目录。如果您为某个目录提供了多个映射, 请以扁平结构(而不是嵌套结构)提供目录。例如,使用 /dir1 和 /dir2,而不是 /dir1 和 /dir1/dir2。

  • SFTP_PERMISSION:目录的访问权限级别。如需只读访问权限,请将此 值设置为 READ_ONLY。如需读写访问权限,请将此值设置为 READ_WRITE。

如需向用户授予对多个存储桶的访问权限,请在 storageDirectoryMappings 列表中提供多个存储桶映射。

HTTP 方法和网址:

PATCH https://ftp.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION_ID/servers/SERVER_ID/users/USERNAME?updateMask=storageDirectoryMappings

请求 JSON 正文:

{
  "storageDirectoryMappings": [
    {
      "bucket": "BUCKET_NAME",
      "bucketPrefix": "BUCKET_PREFIX",
      "directory": "DIRECTORY",
      "permission": "SFTP_PERMISSION"
    }
  ]
}

如需发送您的请求,请展开以下选项之一:

响应会识别 长时间运行的操作。 更新用户需要几秒钟的时间。

如果用户有活跃的 SFTP 连接, 则可能需要断开连接,然后重新连接,更新后的存储桶 设置才会生效。

客户端库

C#

如需了解如何安装和使用 Cloud FTP 的客户端库,请参阅 Cloud FTP 客户端库。 如需了解详情,请参阅 Cloud FTP C# API 参考文档。

如需向 Cloud FTP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅 为本地开发环境设置身份验证。

using Google.Cloud.Ftp.V1;
using Google.LongRunning;
using Google.Protobuf.WellKnownTypes;
using System.Threading.Tasks;

public sealed partial class GeneratedCloudFtpClientSnippets
{
    /// <summary>Snippet for UpdateUserAsync</summary>
    /// <remarks>
    /// This snippet has been automatically generated and should be regarded as a code template only.
    /// It will require modifications to work:
    /// - It may require correct/in-range values for request initialization.
    /// - It may require specifying regional endpoints when creating the service client as shown in
    ///   https://cloud.google.com/dotnet/docs/reference/help/client-configuration#endpoint.
    /// </remarks>
    public async Task UpdateUserAsync()
    {
        // Create client
        CloudFtpClient cloudFtpClient = await CloudFtpClient.CreateAsync();
        // Initialize request argument(s)
        User user = new User();
        FieldMask updateMask = new FieldMask();
        // Make the request
        Operation<User, OperationMetadata> response = await cloudFtpClient.UpdateUserAsync(user, updateMask);

        // Poll until the returned long-running operation is complete
        Operation<User, OperationMetadata> completedResponse = await response.PollUntilCompletedAsync();
        // Retrieve the operation result
        User result = completedResponse.Result;

        // Or get the name of the operation
        string operationName = response.Name;
        // This name can be stored, then the long-running operation retrieved later by name
        Operation<User, OperationMetadata> retrievedResponse = await cloudFtpClient.PollOnceUpdateUserAsync(operationName);
        // Check if the retrieved long-running operation has completed
        if (retrievedResponse.IsCompleted)
        {
            // If it has completed, then access the result
            User retrievedResult = retrievedResponse.Result;
        }
    }
}

Go

如需了解如何安装和使用 Cloud FTP 的客户端库,请参阅 Cloud FTP 客户端库。 如需了解详情,请参阅 Cloud FTP Go API 参考文档。

如需向 Cloud FTP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅 为本地开发环境设置身份验证。


//go:build examples

package main

import (
	"context"

	ftp "cloud.google.com/go/ftp/apiv1"
	ftppb "cloud.google.com/go/ftp/apiv1/ftppb"
)

func main() {
	ctx := context.Background()
	// This snippet has been automatically generated and should be regarded as a code template only.
	// It will require modifications to work:
	// - It may require correct/in-range values for request initialization.
	// - It may require specifying regional endpoints when creating the service client as shown in:
	//   https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
	c, err := ftp.NewCloudFtpRESTClient(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	defer c.Close()

	req := &ftppb.UpdateUserRequest{
		// TODO: Fill request struct fields.
		// See https://pkg.go.dev/cloud.google.com/go/ftp/apiv1/ftppb#UpdateUserRequest.
	}
	op, err := c.UpdateUser(ctx, req)
	if err != nil {
		// TODO: Handle error.
	}

	resp, err := op.Wait(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	// TODO: Use resp.
	_ = resp
}

Java

如需了解如何安装和使用 Cloud FTP 的客户端库,请参阅 Cloud FTP 客户端库。 如需了解详情,请参阅 Cloud FTP Java API 参考文档。

如需向 Cloud FTP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅 为本地开发环境设置身份验证。

import com.google.api.core.ApiFuture;
import com.google.cloud.ftp.v1.CloudFtpClient;
import com.google.cloud.ftp.v1.UpdateUserRequest;
import com.google.cloud.ftp.v1.User;
import com.google.longrunning.Operation;
import com.google.protobuf.FieldMask;

public class AsyncUpdateUser {

  public static void main(String[] args) throws Exception {
    asyncUpdateUser();
  }

  public static void asyncUpdateUser() throws Exception {
    // This snippet has been automatically generated and should be regarded as a code template only.
    // It will require modifications to work:
    // - It may require correct/in-range values for request initialization.
    // - It may require specifying regional endpoints when creating the service client as shown in
    // https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library
    try (CloudFtpClient cloudFtpClient = CloudFtpClient.create()) {
      UpdateUserRequest request =
          UpdateUserRequest.newBuilder()
              .setUpdateMask(FieldMask.newBuilder().build())
              .setUser(User.newBuilder().build())
              .build();
      ApiFuture<Operation> future = cloudFtpClient.updateUserCallable().futureCall(request);
      // Do something.
      Operation response = future.get();
    }
  }
}

Node.js

如需了解如何安装和使用 Cloud FTP 的客户端库,请参阅 Cloud FTP 客户端库。 如需了解详情,请参阅 Cloud FTP Node.js API 参考文档。

如需向 Cloud FTP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅 为本地开发环境设置身份验证。

/**
 * This snippet has been automatically generated and should be regarded as a code template only.
 * It will require modifications to work.
 * It may require correct/in-range values for request initialization.
 * TODO(developer): Uncomment these variables before running the sample.
 */
/**
 *  Optional. Field mask is used to specify the fields to be overwritten in the
 *  User resource by the update.
 *  The fields specified in the update_mask are relative to the resource, not
 *  the full request. A field will be overwritten if it is in the mask. If the
 *  user does not provide a mask then all fields present in the request will be
 *  overwritten.
 */
// const updateMask = {}
/**
 *  Required. The resource being updated
 */
// const user = {}

// Imports the Ftp library
const {CloudFtpClient} = require('@google-cloud/ftp').v1;

// Instantiates a client
const ftpClient = new CloudFtpClient();

async function callUpdateUser() {
  // Construct request
  const request = {
    user,
  };

  // Run request
  const [operation] = await ftpClient.updateUser(request);
  const [response] = await operation.promise();
  console.log(response);
}

callUpdateUser();

PHP

如需了解如何安装和使用 Cloud FTP 的客户端库,请参阅 Cloud FTP 客户端库。 如需了解详情,请参阅 Cloud FTP PHP API 参考文档。

如需向 Cloud FTP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅 为本地开发环境设置身份验证。

use Google\ApiCore\ApiException;
use Google\ApiCore\OperationResponse;
use Google\Cloud\Ftp\V1\Client\CloudFtpClient;
use Google\Cloud\Ftp\V1\StorageDirectoryMapping;
use Google\Cloud\Ftp\V1\StorageDirectoryMapping\Permission;
use Google\Cloud\Ftp\V1\UpdateUserRequest;
use Google\Cloud\Ftp\V1\User;
use Google\Cloud\Ftp\V1\UserCredential;
use Google\Cloud\Ftp\V1\UserCredential\Type;
use Google\Rpc\Status;

/**
 * Updates the parameters of a single User.
 *
 * @param string $userCustomerServiceAccount             Service account in customer project attached to this SFTP User.
 * @param string $userUserCredentialsCredentialName      Name of the user credential.
 * @param int    $userUserCredentialsCredentialType      Type of credential.
 * @param string $userStorageDirectoryMappingsBucket     Name of the bucket.
 * @param string $userStorageDirectoryMappingsDirectory  Directory where the user lands in the SFTP server.
 * @param int    $userStorageDirectoryMappingsPermission Permission to the bucket.
 */
function update_user_sample(
    string $userCustomerServiceAccount,
    string $userUserCredentialsCredentialName,
    int $userUserCredentialsCredentialType,
    string $userStorageDirectoryMappingsBucket,
    string $userStorageDirectoryMappingsDirectory,
    int $userStorageDirectoryMappingsPermission
): void {
    // Create a client.
    $cloudFtpClient = new CloudFtpClient();

    // Prepare the request message.
    $userCredential = (new UserCredential())
        ->setCredentialName($userUserCredentialsCredentialName)
        ->setCredentialType($userUserCredentialsCredentialType);
    $userUserCredentials = [$userCredential];
    $storageDirectoryMapping = (new StorageDirectoryMapping())
        ->setBucket($userStorageDirectoryMappingsBucket)
        ->setDirectory($userStorageDirectoryMappingsDirectory)
        ->setPermission($userStorageDirectoryMappingsPermission);
    $userStorageDirectoryMappings = [$storageDirectoryMapping];
    $user = (new User())
        ->setCustomerServiceAccount($userCustomerServiceAccount)
        ->setUserCredentials($userUserCredentials)
        ->setStorageDirectoryMappings($userStorageDirectoryMappings);
    $request = (new UpdateUserRequest())
        ->setUser($user);

    // Call the API and handle any network failures.
    try {
        /** @var OperationResponse $response */
        $response = $cloudFtpClient->updateUser($request);
        $response->pollUntilComplete();

        if ($response->operationSucceeded()) {
            /** @var User $result */
            $result = $response->getResult();
            printf('Operation successful with response data: %s' . PHP_EOL, $result->serializeToJsonString());
        } else {
            /** @var Status $error */
            $error = $response->getError();
            printf('Operation failed with error data: %s' . PHP_EOL, $error->serializeToJsonString());
        }
    } catch (ApiException $ex) {
        printf('Call failed with message: %s' . PHP_EOL, $ex->getMessage());
    }
}

/**
 * Helper to execute the sample.
 *
 * This sample has been automatically generated and should be regarded as a code
 * template only. It will require modifications to work:
 *  - It may require correct/in-range values for request initialization.
 *  - It may require specifying regional endpoints when creating the service client,
 *    please see the apiEndpoint client configuration option for more details.
 */
function callSample(): void
{
    $userCustomerServiceAccount = '[CUSTOMER_SERVICE_ACCOUNT]';
    $userUserCredentialsCredentialName = '[CREDENTIAL_NAME]';
    $userUserCredentialsCredentialType = Type::TYPE_UNSPECIFIED;
    $userStorageDirectoryMappingsBucket = '[BUCKET]';
    $userStorageDirectoryMappingsDirectory = '[DIRECTORY]';
    $userStorageDirectoryMappingsPermission = Permission::PERMISSION_UNSPECIFIED;

    update_user_sample(
        $userCustomerServiceAccount,
        $userUserCredentialsCredentialName,
        $userUserCredentialsCredentialType,
        $userStorageDirectoryMappingsBucket,
        $userStorageDirectoryMappingsDirectory,
        $userStorageDirectoryMappingsPermission
    );
}

Python

如需了解如何安装和使用 Cloud FTP 的客户端库,请参阅 Cloud FTP 客户端库。 如需了解详情,请参阅 Cloud FTP Python API 参考文档。

如需向 Cloud FTP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅 为本地开发环境设置身份验证。

# This snippet has been automatically generated and should be regarded as a
# code template only.
# It will require modifications to work:
# - It may require correct/in-range values for request initialization.
# - It may require specifying regional endpoints when creating the service
#   client as shown in:
#   https://googleapis.dev/python/google-api-core/latest/client_options.html
from google.cloud import ftp_v1


def sample_update_user():
    # Create a client
    client = ftp_v1.CloudFtpClient()

    # Initialize request argument(s)
    user = ftp_v1.User()
    user.customer_service_account = "customer_service_account_value"
    user.user_credentials.credential_name = "credential_name_value"
    user.user_credentials.credential_type = "PUBLIC_KEY"
    user.storage_directory_mappings.bucket = "bucket_value"
    user.storage_directory_mappings.directory = "directory_value"
    user.storage_directory_mappings.permission = "READ_WRITE"

    request = ftp_v1.UpdateUserRequest(
        user=user,
    )

    # Make the request
    operation = client.update_user(request=request)

    print("Waiting for operation to complete...")

    response = operation.result()

    # Handle the response
    print(response)

Ruby

如需了解如何安装和使用 Cloud FTP 的客户端库,请参阅 Cloud FTP 客户端库。 如需了解详情,请参阅 Cloud FTP Ruby API 参考文档。

如需向 Cloud FTP 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅 为本地开发环境设置身份验证。

require "google/cloud/ftp/v1"

##
# Snippet for the update_user call in the CloudFtp service
#
# This snippet has been automatically generated and should be regarded as a code
# template only. It will require modifications to work:
# - It may require correct/in-range values for request initialization.
# - It may require specifying regional endpoints when creating the service
# client as shown in https://cloud.google.com/ruby/docs/reference.
#
# This is an auto-generated example demonstrating basic usage of
# Google::Cloud::Ftp::V1::CloudFtp::Rest::Client#update_user.
#
def update_user
  # Create a client object. The client can be reused for multiple calls.
  client = Google::Cloud::Ftp::V1::CloudFtp::Rest::Client.new

  # Create a request. To set request fields, pass in keyword arguments.
  request = Google::Cloud::Ftp::V1::UpdateUserRequest.new

  # Call the update_user method.
  result = client.update_user request

  # The returned object is of type Gapic::Operation. You can use it to
  # check the status of an operation, cancel it, or wait for results.
  # Here is how to wait for a response.
  result.wait_until_done! timeout: 60
  if result.response?
    p result.response
  else
    puts "No response received."
  end
end