3.3. 使用 S3 API 访问 Ceph 对象网关


作为开发者,您必须配置对 Ceph 对象网关和安全令牌服务(STS)的访问权限,然后才能开始使用 Amazon S3 API。

3.3.1. 先决条件

  • 一个正在运行的 Red Hat Ceph Storage 集群。
  • 正在运行的 Ceph 对象网关.
  • RESTful 客户端。

3.3.2. S3 身份验证

对 Ceph 对象网关的请求可以是经过身份验证的用户或未经身份验证的请求。Ceph 对象网关假定匿名用户发送了未经身份验证的请求。Ceph 对象网关支持 ACL。

对于大多数用例,客户端使用现有开源库,如 Amazon SDK 的 AmazonS3Client 用于 Java 和 Python Boto。使用开源库,只需传递访问密钥和密钥,库会为您构建请求标头和身份验证签名。但是,您可以创建请求并签署它们。

在向 Ceph 对象网关服务器发送前,在请求中包括访问密钥和基于 64 编码的消息身份验证代码(HMAC)的要求。Ceph 对象网关使用兼容 S3 的身份验证方法。

示例

HTTP/1.1
PUT /buckets/bucket/object.mpeg
Host: cname.domain.com
Date: Mon, 2 Jan 2012 00:01:01 +0000
Content-Encoding: mpeg
Content-Length: 9999999

Authorization: AWS ACCESS_KEY:HASH_OF_HEADER_AND_SECRET

在上例中,将 ACCESS_KEY 替换为 access key ID 的值,后跟一个冒号(:)。将 HASH_OF_HEADER_AND_SECRET 替换为一个规范标头字符串的哈希值,以及与访问密钥 ID 对应的 secret。

生成标头字符串和 secret 的哈希值

生成标头字符串和 secret 的哈希值:

  1. 获取标头字符串的值。
  2. 将请求标头字符串规范化为规范形式。
  3. 使用 SHA-1 哈希算法生成 HMAC。
  4. hmac 结果编码为 base-64。

规范化标头

将标头规范化为规范形式:

  1. 获取 所有内容 标题。
  2. 删除除 content-typecontent-md5 外的所有 content- 标头。
  3. 确保 content- 标头名称是小写。
  4. 以字典顺序对 content- 标题排序。
  5. 确保带有 Date 标头,并确保指定的日期使用 GMT 而不是偏移量。
  6. 获取以 x-amz- 开头的所有标题。
  7. 确保 x-amz- 标头都是小写。
  8. 以数字方式对 x-amz- 标头进行排序。
  9. 将同一字段名称的多个实例合并到一个字段中,并使用逗号分隔字段值。
  10. 使用单个空格替换标题值中的空格和换行符。
  11. 在冒号前后删除空格。
  12. 在每个标头后面添加一个新行。
  13. 将标头合并回请求标头。

HASH_OF_HEADER_AND_SECRET 替换为 base-64 编码的 HMAC 字符串。

其它资源

3.3.3. 服务器侧加密(SSE)

Ceph 对象网关支持为 S3 应用编程接口(API)上传对象的服务器端加密。服务器端加密意味着 S3 客户端以未加密的形式通过 HTTP 发送数据,而 Ceph 对象网关以加密的形式将数据存储在 Red Hat Ceph Storage 集群中。

注意
  • 红帽不支持静态大型对象(SLO)或动态大对象(DLO)的 S3 对象加密。
  • 目前,没有 Server-Side 加密(SSE)模式支持 CopyObject。它目前正在开发 [BZ#2149450]
重要

若要使用加密,客户端请求需要通过 SSL 连接发送请求。除非 Ceph 对象网关使用 SSL,否则红帽不支持从客户端进行 S3 加密。但是,出于测试目的,管理员可以使用 ceph config set client.rgw 命令,在测试期间禁用 SSL,在运行时将 rgw_crypt_require_ssl 配置设置设置为 false,然后重新启动 Ceph 对象网关实例。

在生产环境中,可能无法通过 SSL 发送加密的请求。在这种情况下,使用 HTTP 和服务器端加密发送请求。

有关如何使用服务器端加密配置 HTTP 的详情,请参考下面的附加资源部分。

S3 多部分使用服务器端加密上传现在在多站点中正确复制。在以前的版本中,此类对象的副本通过解密损坏,您可以使用 radosgw-admin bucket resync encrypted multipart --bucket-name BUCKET_NAME 命令来识别多部分上传。此命令扫描加密多部分对象的主要非复制副本。对于每个对象,任何识别对象的 LastModified 时间戳都会被 1ns 递增,以便对等区再次复制它。对于使用 SSE 的多站点部署,请在升级所有区域后针对每个区域中的每个存储桶运行这个命令。这样可确保使用 SSE 在多站点中正确复制 S3 多部分上传。

管理加密密钥有两个选项:

客户提供的键

在使用客户提供的密钥时,S3 客户端会传递加密密钥以及每个请求来读取或写入加密数据。客户负责管理这些密钥。客户必须记住用于加密每个对象的 Ceph 对象网关的关键是什么。

Ceph 对象网关根据 Amazon SSE-C 规范在 S3 API 中实施客户提供的关键行为。

由于客户处理密钥管理,并且 S3 客户端将密钥传递到 Ceph 对象网关,因此 Ceph 对象网关不需要特殊配置来支持这种加密模式。

密钥管理服务

在使用密钥管理服务时,安全密钥管理服务存储密钥,Ceph 对象网关则按需检索密钥,为数据加密或解密请求提供服务。

Ceph 对象网关根据 Amazon SSE-KMS 规范在 S3 API 中实施关键管理服务行为。

重要

目前,唯一测试的关键管理实施是 HashiCorp Vault 和 OpenStack Barbican。但是,OpenStack Barbican 是一个技术预览,不支持在生产环境中使用。

3.3.4. S3 访问控制列表

Ceph 对象网关支持 S3 兼容访问控制列表(ACL)功能。ACL 是访问权限列表,可指定用户可以对存储桶或对象执行的操作。在应用到存储桶而不是应用到对象时,每个授权都有不同的意义:

表 3.1. 用户操作
权限BucketObject

READ

Grantee 可以列出存储桶中的对象。

Grantee 可以读取对象。

Grantee 可以编写或删除存储桶中的对象。

不适用

READ_ACP

Grantee 可以读取存储桶 ACL。

Grantee 可以读取对象 ACL。

WRITE_ACP

Grantee 可以编写存储桶 ACL。

Grantee 可以写入对象 ACL。

FULL_CONTROL

Grantee 具有存储桶中对象的完整权限。

Grantee 可以读取和写入对象 ACL。

3.3.5. 使用 S3 准备对 Ceph 对象网关的访问

在尝试访问网关服务器前,您必须在 Ceph 对象网关节点上遵循一些前提条件。

先决条件

  • 安装 Ceph 对象网关软件.
  • Ceph 对象网关节点的根级别访问权限.

流程

  1. root 用户身份,在防火墙上打开端口 8080

    [root@rgw ~]# firewall-cmd --zone=public --add-port=8080/tcp --permanent
    [root@rgw ~]# firewall-cmd --reload
  2. 在您要用于网关的 DNS 服务器中添加通配符,如 Object Gateway Configuration and Administration Guide 所述。

    您还可以为本地 DNS 缓存设置网关节点。要做到这一点,请执行以下步骤:

    1. root 用户身份,安装和设置 dnsmasq

      [root@rgw ~]# yum install dnsmasq
      [root@rgw ~]# echo "address=/.FQDN_OF_GATEWAY_NODE/IP_OF_GATEWAY_NODE" | tee --append /etc/dnsmasq.conf
      [root@rgw ~]# systemctl start dnsmasq
      [root@rgw ~]# systemctl enable dnsmasq

      IP_OF_GATEWAY_NODEFQDN_OF_GATEWAY_NODE 替换为网关节点的 IP 地址和 FQDN。

    2. 作为 root 用户,停止 NetworkManager:

      [root@rgw ~]# systemctl stop NetworkManager
      [root@rgw ~]# systemctl disable NetworkManager
    3. root 用户身份,将网关服务器的 IP 设置为名称服务器:

      [root@rgw ~]# echo "DNS1=IP_OF_GATEWAY_NODE" | tee --append /etc/sysconfig/network-scripts/ifcfg-eth0
      [root@rgw ~]# echo "IP_OF_GATEWAY_NODE FQDN_OF_GATEWAY_NODE" | tee --append /etc/hosts
      [root@rgw ~]# systemctl restart network
      [root@rgw ~]# systemctl enable network
      [root@rgw ~]# systemctl restart dnsmasq

      IP_OF_GATEWAY_NODEFQDN_OF_GATEWAY_NODE 替换为网关节点的 IP 地址和 FQDN。

    4. 验证子域请求:

      [user@rgw ~]$ ping mybucket.FQDN_OF_GATEWAY_NODE

      FQDN_OF_GATEWAY_NODE 替换为网关节点的 FQDN。

      警告

      为本地 DNS 缓存设置网关服务器仅用于测试目的。执行此操作后,您无法访问外部网络。强烈建议您为 Red Hat Ceph Storage 集群和网关节点使用正确的 DNS 服务器。

  3. Object Gateway Configuration and Administration Guide 所述,小心创建 radosgw 用于用于对 S3 进行访问,并复制生成的 access_keysecret_key。您需要这些密钥进行 S3 访问和随后的 bucket 管理任务。

3.3.6. 使用 Ruby AWS S3 访问 Ceph 对象网关

您可以使用 Ruby 编程语言以及 aws-s3 gem 用于 S3 访问。在用于通过 Ruby AWS::S3 访问 Ceph 对象网关服务器的节点上执行下方所述的步骤。

先决条件

  • Ceph 对象网关用户级访问权限.
  • 访问 Ceph 对象网关的 root 级别访问节点。
  • 互联网访问。

流程

  1. 安装 ruby 软件包:

    [root@dev ~]# yum install ruby
    注意

    以上命令将安装 ruby 及其基本依赖项,如 rubygemsruby-libs。如果某种方式命令没有安装所有依赖项,请单独安装它们。

  2. 安装 aws-s3 Ruby 软件包:

    [root@dev ~]# gem install aws-s3
  3. 创建项目目录:

    [user@dev ~]$ mkdir ruby_aws_s3
    [user@dev ~]$ cd ruby_aws_s3
  4. 创建连接文件:

    [user@dev ~]$ vim conn.rb
  5. 将以下内容粘贴到 conn.rb 文件中:

    语法

    #!/usr/bin/env ruby
    
    require 'aws/s3'
    require 'resolv-replace'
    
    AWS::S3::Base.establish_connection!(
            :server            => 'FQDN_OF_GATEWAY_NODE',
            :port           => '8080',
            :access_key_id     => 'MY_ACCESS_KEY',
            :secret_access_key => 'MY_SECRET_KEY'
    )

    FQDN_OF_GATEWAY_NODE 替换为 Ceph 对象网关节点的 FQDN。将 MY_ACCESS_KEYMY_SECRET_KEY 替换为您在创建 radosgw 用户来访问 S3 时生成的 access_keysecret_key,如 Red Hat Ceph Storage Object Gateway 配置和管理指南中所述。

    示例

    #!/usr/bin/env ruby
    
    require 'aws/s3'
    require 'resolv-replace'
    
    AWS::S3::Base.establish_connection!(
            :server            => 'testclient.englab.pnq.redhat.com',
            :port           => '8080',
            :access_key_id     => '98J4R9P22P5CDL65HKP8',
            :secret_access_key => '6C+jcaP0dp0+FZfrRNgyGA9EzRy25pURldwje049'
    )

    保存文件并退出编辑器。

  6. 使文件可执行:

    [user@dev ~]$ chmod +x conn.rb
  7. 运行该文件:

    [user@dev ~]$ ./conn.rb | echo $?

    如果您在文件中正确提供了值,命令的输出将是 0

  8. 创建存储桶的新文件:

    [user@dev ~]$ vim create_bucket.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    AWS::S3::Bucket.create('my-new-bucket1')

    保存文件并退出编辑器。

  9. 使文件可执行:

    [user@dev ~]$ chmod +x create_bucket.rb
  10. 运行该文件:

    [user@dev ~]$ ./create_bucket.rb

    如果命令的输出为 true,这表示 bucket my-new-bucket1 已创建成功。

  11. 创建用于列出所拥有的存储桶的新文件:

    [user@dev ~]$ vim list_owned_buckets.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    AWS::S3::Service.buckets.each do |bucket|
            puts "{bucket.name}\t{bucket.creation_date}"
    end

    保存文件并退出编辑器。

  12. 使文件可执行:

    [user@dev ~]$ chmod +x list_owned_buckets.rb
  13. 运行该文件:

    [user@dev ~]$ ./list_owned_buckets.rb

    输出应类似如下:

    my-new-bucket1 2020-01-21 10:33:19 UTC
  14. 创建用于创建对象的新文件:

    [user@dev ~]$ vim create_object.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    AWS::S3::S3Object.store(
            'hello.txt',
            'Hello World!',
            'my-new-bucket1',
            :content_type => 'text/plain'
    )

    保存文件并退出编辑器。

  15. 使文件可执行:

    [user@dev ~]$ chmod +x create_object.rb
  16. 运行该文件:

    [user@dev ~]$ ./create_object.rb

    这将创建一个含有字符串 Hello World! 的文件 hello.txt

  17. 创建用于列出存储桶内容的新文件:

    [user@dev ~]$ vim list_bucket_content.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    new_bucket = AWS::S3::Bucket.find('my-new-bucket1')
    new_bucket.each do |object|
            puts "{object.key}\t{object.about['content-length']}\t{object.about['last-modified']}"
    end

    保存文件并退出编辑器。

  18. 使文件成为可执行文件。

    [user@dev ~]$ chmod +x list_bucket_content.rb
  19. 运行该文件:

    [user@dev ~]$ ./list_bucket_content.rb

    输出将类似如下:

    hello.txt    12    Fri, 22 Jan 2020 15:54:52 GMT
  20. 创建用于删除空存储桶的新文件:

    [user@dev ~]$ vim del_empty_bucket.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    AWS::S3::Bucket.delete('my-new-bucket1')

    保存文件并退出编辑器。

  21. 使文件可执行:

    [user@dev ~]$ chmod +x del_empty_bucket.rb
  22. 运行该文件:

    [user@dev ~]$ ./del_empty_bucket.rb | echo $?

    如果删除了存储桶,命令会返回 0 作为输出。

    注意

    编辑 create_bucket.rb 文件,以创建空的 bucket,例如 my-new-bucket4、 my-new-bucket5。然后,在尝试删除空存储桶前相应地编辑上述 del_empty_bucket.rb 文件。

  23. 创建用于删除非空存储桶的新文件:

    [user@dev ~]$ vim del_non_empty_bucket.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    AWS::S3::Bucket.delete('my-new-bucket1', :force => true)

    保存文件并退出编辑器。

  24. 使文件可执行:

    [user@dev ~]$ chmod +x del_non_empty_bucket.rb
  25. 运行该文件:

    [user@dev ~]$ ./del_non_empty_bucket.rb | echo $?

    如果删除了存储桶,命令会返回 0 作为输出。

  26. 创建用于删除对象的新文件:

    [user@dev ~]$ vim delete_object.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    AWS::S3::S3Object.delete('hello.txt', 'my-new-bucket1')

    保存文件并退出编辑器。

  27. 使文件可执行:

    [user@dev ~]$ chmod +x delete_object.rb
  28. 运行该文件:

    [user@dev ~]$ ./delete_object.rb

    这将删除对象 hello.txt

3.3.7. 使用 Ruby AWS SDK 访问 Ceph 对象网关

您可以使用 Ruby 编程语言以及 aws-sdk gem 用于 S3 访问。在用于通过 Ruby AWS::SDK 访问 Ceph 对象网关服务器的节点上执行下方所述的步骤。

先决条件

  • Ceph 对象网关用户级访问权限.
  • 访问 Ceph 对象网关的 root 级别访问节点。
  • 互联网访问。

流程

  1. 安装 ruby 软件包:

    [root@dev ~]# yum install ruby
    注意

    以上命令将安装 ruby 及其基本依赖项,如 rubygemsruby-libs。如果某种方式命令没有安装所有依赖项,请单独安装它们。

  2. 安装 aws-sdk Ruby 软件包:

    [root@dev ~]# gem install aws-sdk
  3. 创建项目目录:

    [user@dev ~]$ mkdir ruby_aws_sdk
    [user@dev ~]$ cd ruby_aws_sdk
  4. 创建连接文件:

    [user@dev ~]$ vim conn.rb
  5. 将以下内容粘贴到 conn.rb 文件中:

    语法

    #!/usr/bin/env ruby
    
    require 'aws-sdk'
    require 'resolv-replace'
    
    Aws.config.update(
            endpoint: 'http://FQDN_OF_GATEWAY_NODE:8080',
            access_key_id: 'MY_ACCESS_KEY',
            secret_access_key: 'MY_SECRET_KEY',
            force_path_style: true,
            region: 'us-east-1'
    )

    FQDN_OF_GATEWAY_NODE 替换为 Ceph 对象网关节点的 FQDN。将 MY_ACCESS_KEYMY_SECRET_KEY 替换为您在创建 radosgw 用户来访问 S3 时生成的 access_keysecret_key,如 Red Hat Ceph Storage Object Gateway 配置和管理指南中所述。

    示例

    #!/usr/bin/env ruby
    
    require 'aws-sdk'
    require 'resolv-replace'
    
    Aws.config.update(
            endpoint: 'http://testclient.englab.pnq.redhat.com:8080',
            access_key_id: '98J4R9P22P5CDL65HKP8',
            secret_access_key: '6C+jcaP0dp0+FZfrRNgyGA9EzRy25pURldwje049',
            force_path_style: true,
            region: 'us-east-1'
    )

    保存文件并退出编辑器。

  6. 使文件可执行:

    [user@dev ~]$ chmod +x conn.rb
  7. 运行该文件:

    [user@dev ~]$ ./conn.rb | echo $?

    如果您在文件中正确提供了值,命令的输出将是 0

  8. 创建存储桶的新文件:

    [user@dev ~]$ vim create_bucket.rb

    将以下内容粘贴到文件中:

    语法

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    s3_client = Aws::S3::Client.new
    s3_client.create_bucket(bucket: 'my-new-bucket2')

    保存文件并退出编辑器。

  9. 使文件可执行:

    [user@dev ~]$ chmod +x create_bucket.rb
  10. 运行该文件:

    [user@dev ~]$ ./create_bucket.rb

    如果命令的输出为 true,这表示 bucket my-new-bucket2 已创建成功。

  11. 创建用于列出所拥有的存储桶的新文件:

    [user@dev ~]$ vim list_owned_buckets.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    s3_client = Aws::S3::Client.new
    s3_client.list_buckets.buckets.each do |bucket|
            puts "{bucket.name}\t{bucket.creation_date}"
    end

    保存文件并退出编辑器。

  12. 使文件可执行:

    [user@dev ~]$ chmod +x list_owned_buckets.rb
  13. 运行该文件:

    [user@dev ~]$ ./list_owned_buckets.rb

    输出应类似如下:

    my-new-bucket2 2020-01-21 10:33:19 UTC
  14. 创建用于创建对象的新文件:

    [user@dev ~]$ vim create_object.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    s3_client = Aws::S3::Client.new
    s3_client.put_object(
            key: 'hello.txt',
            body: 'Hello World!',
            bucket: 'my-new-bucket2',
            content_type: 'text/plain'
    )

    保存文件并退出编辑器。

  15. 使文件可执行:

    [user@dev ~]$ chmod +x create_object.rb
  16. 运行该文件:

    [user@dev ~]$ ./create_object.rb

    这将创建一个含有字符串 Hello World! 的文件 hello.txt

  17. 创建用于列出存储桶内容的新文件:

    [user@dev ~]$ vim list_bucket_content.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    s3_client = Aws::S3::Client.new
    s3_client.list_objects(bucket: 'my-new-bucket2').contents.each do |object|
            puts "{object.key}\t{object.size}"
    end

    保存文件并退出编辑器。

  18. 使文件成为可执行文件。

    [user@dev ~]$ chmod +x list_bucket_content.rb
  19. 运行该文件:

    [user@dev ~]$ ./list_bucket_content.rb

    输出将类似如下:

    hello.txt    12    Fri, 22 Jan 2020 15:54:52 GMT
  20. 创建用于删除空存储桶的新文件:

    [user@dev ~]$ vim del_empty_bucket.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    s3_client = Aws::S3::Client.new
    s3_client.delete_bucket(bucket: 'my-new-bucket2')

    保存文件并退出编辑器。

  21. 使文件可执行:

    [user@dev ~]$ chmod +x del_empty_bucket.rb
  22. 运行该文件:

    [user@dev ~]$ ./del_empty_bucket.rb | echo $?

    如果删除了存储桶,命令会返回 0 作为输出。

    注意

    编辑 create_bucket.rb 文件,以创建空的 bucket,例如 my-new-bucket6my-new-bucket7。然后,在尝试删除空存储桶前相应地编辑上述 del_empty_bucket.rb 文件。

  23. 创建用于删除非空存储桶的新文件:

    [user@dev ~]$ vim del_non_empty_bucket.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    s3_client = Aws::S3::Client.new
    Aws::S3::Bucket.new('my-new-bucket2', client: s3_client).clear!
    s3_client.delete_bucket(bucket: 'my-new-bucket2')

    保存文件并退出编辑器。

  24. 使文件可执行:

    [user@dev ~]$ chmod +x del_non_empty_bucket.rb
  25. 运行该文件:

    [user@dev ~]$ ./del_non_empty_bucket.rb | echo $?

    如果删除了存储桶,命令会返回 0 作为输出。

  26. 创建用于删除对象的新文件:

    [user@dev ~]$ vim delete_object.rb

    将以下内容粘贴到文件中:

    #!/usr/bin/env ruby
    
    load 'conn.rb'
    
    s3_client = Aws::S3::Client.new
    s3_client.delete_object(key: 'hello.txt', bucket: 'my-new-bucket2')

    保存文件并退出编辑器。

  27. 使文件可执行:

    [user@dev ~]$ chmod +x delete_object.rb
  28. 运行该文件:

    [user@dev ~]$ ./delete_object.rb

    这将删除对象 hello.txt

3.3.8. 使用 PHP 访问 Ceph 对象网关

您可以使用 PHP 脚本进行 S3 访问。此流程提供一些示例 PHP 脚本来执行各种任务,如删除存储桶或对象。

重要

以下给出的示例针对 php v5.4.16aws-sdk v2.8.24 测试。不要使用最新版本的 aws-sdk for php,因为它需要没有包括在 RHEL 7 默认仓库中的 php >= 5.5+.php 5.5。如果要使用 php 5.5,则必须启用 epel 和其他第三方存储库。另外,php 5.5 和最新版本的 aws-sdk 的配置选项也不同。

先决条件

  • 根级访问开发工作站。
  • 互联网访问。

流程

  1. 安装 php 软件包:

    [root@dev ~]# yum install php
  2. 下载适用于 PHP 的 aws-sdk 的 zip 存档并解压缩。
  3. 创建项目目录:

    [user@dev ~]$ mkdir php_s3
    [user@dev ~]$ cd php_s3
  4. 将提取的 aws 目录复制到项目目录中。例如:

    [user@dev ~]$ cp -r ~/Downloads/aws/ ~/php_s3/
  5. 创建连接文件:

    [user@dev ~]$ vim conn.php
  6. 将以下内容粘贴到 conn.php 文件中:

    语法

    <?php
    define('AWS_KEY', 'MY_ACCESS_KEY');
    define('AWS_SECRET_KEY', 'MY_SECRET_KEY');
    define('HOST', 'FQDN_OF_GATEWAY_NODE');
    define('PORT', '8080');
    
    // require the AWS SDK for php library
    require '/PATH_TO_AWS/aws-autoloader.php';
    
    use Aws\S3\S3Client;
    
    // Establish connection with host using S3 Client
    client = S3Client::factory(array(
        'base_url' => HOST,
        'port' => PORT,
        'key'      => AWS_KEY,
        'secret'   => AWS_SECRET_KEY
    ));
    ?>

    FQDN_OF_GATEWAY_NODE 替换为网关节点的 FQDN。将 MY_ACCESS_KEYMY_SECRET_KEY 替换为创建 radosgw 用户来访问 S3 时生成的 access_keysecret_key,如 Red Hat Ceph Storage Object Gateway 配置和管理指南 中所述。将 PATH_TO_AWS 替换为您复制到 php 项目目录的提取 aws 目录的绝对路径。

    保存文件并退出编辑器。

  7. 运行该文件:

    [user@dev ~]$ php -f conn.php | echo $?

    如果您在文件中正确提供了值,命令的输出将是 0

  8. 创建存储桶的新文件:

    [user@dev ~]$ vim create_bucket.php

    将以下内容粘贴到新文件中:

    语法

    <?php
    
    include 'conn.php';
    
    client->createBucket(array('Bucket' => 'my-new-bucket3'));
    
    ?>

    保存文件并退出编辑器。

  9. 运行该文件:

    [user@dev ~]$ php -f create_bucket.php
  10. 创建用于列出所拥有的存储桶的新文件:

    [user@dev ~]$ vim list_owned_buckets.php

    将以下内容粘贴到文件中:

    语法

    <?php
    
    include 'conn.php';
    
    blist = client->listBuckets();
    echo "Buckets belonging to " . blist['Owner']['ID'] . ":\n";
    foreach (blist['Buckets'] as b) {
        echo "{b['Name']}\t{b['CreationDate']}\n";
    }
    
    ?>

    保存文件并退出编辑器。

  11. 运行该文件:

    [user@dev ~]$ php -f list_owned_buckets.php

    输出应类似于如下:

    my-new-bucket3 2020-01-21 10:33:19 UTC
  12. 首先创建名为 hello.txt 的源文件,以创建对象:

    [user@dev ~]$ echo "Hello World!" > hello.txt
  13. 创建新 php 文件:

    [user@dev ~]$ vim create_object.php

    将以下内容粘贴到文件中:

    语法

    <?php
    
    include 'conn.php';
    
    key         = 'hello.txt';
    source_file = './hello.txt';
    acl         = 'private';
    bucket      = 'my-new-bucket3';
    client->upload(bucket, key, fopen(source_file, 'r'), acl);
    
    ?>

    保存文件并退出编辑器。

  14. 运行该文件:

    [user@dev ~]$ php -f create_object.php

    这将在 bucket my-new-bucket3 中创建对象 hello.txt

  15. 创建用于列出存储桶内容的新文件:

    [user@dev ~]$ vim list_bucket_content.php

    将以下内容粘贴到文件中:

    语法

    <?php
    
    include 'conn.php';
    
    o_iter = client->getIterator('ListObjects', array(
        'Bucket' => 'my-new-bucket3'
    ));
    foreach (o_iter as o) {
        echo "{o['Key']}\t{o['Size']}\t{o['LastModified']}\n";
    }
    ?>

    保存文件并退出编辑器。

  16. 运行该文件:

    [user@dev ~]$ php -f list_bucket_content.php

    输出类似如下:

    hello.txt    12    Fri, 22 Jan 2020 15:54:52 GMT
  17. 创建用于删除空存储桶的新文件:

    [user@dev ~]$ vim del_empty_bucket.php

    将以下内容粘贴到文件中:

    语法

    <?php
    
    include 'conn.php';
    
    client->deleteBucket(array('Bucket' => 'my-new-bucket3'));
    ?>

    保存文件并退出编辑器。

  18. 运行该文件:

    [user@dev ~]$ php -f del_empty_bucket.php | echo $?

    如果删除了存储桶,命令会返回 0 作为输出。

    注意

    编辑 create_bucket.php 文件,以创建空的 bucket,如 my-new-bucket4、 my-new-bucket5。然后,在尝试删除空存储桶前相应地编辑上述 del_empty_bucket.php 文件。

    重要

    PHP 2 和 aws-sdk 的新版本不支持删除非空存储桶。

  19. 创建用于删除对象的新文件:

    [user@dev ~]$ vim delete_object.php

    将以下内容粘贴到文件中:

    语法

    <?php
    
    include 'conn.php';
    
    client->deleteObject(array(
        'Bucket' => 'my-new-bucket3',
        'Key'    => 'hello.txt',
    ));
    ?>

    保存文件并退出编辑器。

  20. 运行该文件:

    [user@dev ~]$ php -f delete_object.php

    这将删除对象 hello.txt

3.3.9. 安全令牌服务

Amazon Web Services 的安全令牌服务(STS)返回一组临时安全凭证来验证用户。Ceph 对象网关实施 STS 应用程序编程接口(API)的子集,为身份和访问管理(IAM)提供临时凭证。使用这些临时凭证,通过在 Ceph 对象网关中使用 STS 引擎来验证 S3 调用。您可以使用 IAM 策略限制临时凭证,该策略是传递给 STS API 的参数。

其它资源

3.3.9.1. 安全令牌服务应用程序编程接口

Ceph 对象网关实施下列安全令牌服务(STS)应用程序编程接口(API):

AssumeRole

此 API 返回一组临时凭证,用于跨帐户访问。这些临时凭证都允许,附加了 AssumeRole API 的 Role 和策略的权限策略。RoleArnRoleSessionName 请求参数是必需的,但其他请求参数是可选的。

RoleArn
描述
假定为 Amazon 资源名(ARN)的角色,长度为 20 到 2048 个字符。
Type
字符串
必需
RoleSessionName
描述
识别要假定的角色会话名称。当不同的主体或不同的原因假设角色时,角色会话名称可以唯一标识一个会话。此参数的值的长度为 2 到 64 个字符。允许使用 =、、、、@- 字符,但不允许有空格。
Type
字符串
必需
policy
描述
以 JSON 格式的身份和访问管理策略(IAM),用于在内联会话中使用。此参数的值的长度为 1 到 2048 个字符。
Type
字符串
必需
DurationSeconds
描述
会话持续时间(以秒为单位),最小值为 900 秒,最大值为 43200 秒。默认值为 3600 秒。
Type
整数
必需
ExternalId
描述
假设另一个帐户的角色时,请提供一个唯一的外部标识符(如果可用)。这个参数的值的长度为 2 到 1224 个字符。
Type
字符串
必需
SerialNumber
描述
用户从关联的多因素身份验证(MFA)设备识别号。参数的值可以是硬件设备或虚拟设备的序列号,长度为 9 到 256 个字符。
Type
字符串
必需
TokenCode
描述
如果信任策略需要 MFA,则从多因素身份验证(MFA)设备生成的值。如果需要 MFA 设备,如果此参数的值为空或过期,则 AssumeRole 调用会返回 "access denied" 错误消息。这个参数的值的固定长度为 6 个字符。
Type
字符串
必需

AssumeRoleWithWebIdentity

此 API 为应用进行身份验证的用户返回一组临时凭据,如 OpenID Connect 或 OAuth 2.0 身份提供程序。RoleArnRoleSessionName 请求参数是必需的,但其他请求参数是可选的。

RoleArn
描述
假定为 Amazon 资源名(ARN)的角色,长度为 20 到 2048 个字符。
类型
字符串
必需
RoleSessionName
描述
识别要假定的角色会话名称。当不同的主体或不同的原因假设角色时,角色会话名称可以唯一标识一个会话。此参数的值的长度为 2 到 64 个字符。允许使用 = 、、、、 @- 字符,但不允许有空格。
Type
字符串
必需
policy
描述
以 JSON 格式的身份和访问管理策略(IAM),用于在内联会话中使用。此参数的值的长度为 1 到 2048 个字符。
Type
字符串
必需
DurationSeconds
描述
会话持续时间(以秒为单位),最小值为 900 秒,最大值为 43200 秒。默认值为 3600 秒。
Type
整数
必需
ProviderId
描述
身份提供程序中域名的完全限定主机组件。此参数的值仅对 OAuth 2.0 访问令牌有效,长度为 4 到 2048 个字符。
Type
字符串
必需
WebIdentityToken
描述
从身份提供程序提供的 OpenID Connect 身份令牌或 OAuth 2.0 访问令牌。此参数的值的长度为 4 到 2048 个字符。
Type
字符串
必需

其它资源

3.3.9.2. 配置安全令牌服务

通过设置 rgw_sts_keyrgw_s3_auth_use_sts 选项,配置与 Ceph 对象网关搭配使用的安全令牌服务(STS)。

注意

S3 和 STS API 共同存在于同一命名空间中,两者都可从 Ceph 对象网关中的同一端点访问。

先决条件

  • 一个正在运行的 Red Hat Ceph Storage 集群。
  • 正在运行的 Ceph 对象网关.
  • Ceph 管理器节点的 root 级别访问。

流程

  1. 为 Ceph 对象网关客户端设置以下配置选项:

    语法

    ceph config set RGW_CLIENT_NAME rgw_sts_key STS_KEY
    ceph config set RGW_CLIENT_NAME rgw_s3_auth_use_sts true

    rgw_sts_key 是用于加密或解密会话令牌的 STS 密钥,且正好为 16 十六进制字符。

    重要

    STS 密钥需要是字母数字。

    示例

    [root@mgr ~]# ceph config set client.rgw rgw_sts_key 7f8fd8dd4700mnop
    [root@mgr ~]# ceph config set client.rgw rgw_s3_auth_use_sts true

  2. 重新启动 Ceph 对象网关,使添加的密钥生效。

    注意

    使用 ceph orch ps 命令的输出,在 NAME 列下获取 SERVICE_TYPEID 信息。

    1. 在存储集群中的单个节点上重启 Ceph 对象网关:

      语法

      systemctl restart ceph-CLUSTER_ID@SERVICE_TYPE.ID.service

      示例

      [root@host01 ~]# systemctl restart ceph-c4b34c6f-8365-11ba-dc31-529020a7702d@rgw.realm.zone.host01.gwasto.service

    2. 在存储集群的所有节点上重启 Ceph 对象网关:

      语法

      ceph orch restart SERVICE_TYPE

      示例

      [ceph: root@host01 /]# ceph orch restart rgw

其它资源

3.3.9.3. 为 OpenID Connect 供应商创建用户

要在 Ceph 对象网关和 OpenID Connect 供应商间建立信任,请创建一个用户实体和角色信任策略。

先决条件

  • Ceph 对象网关节点的用户级访问权限。

流程

  1. 创建新 Ceph 用户:

    语法

    radosgw-admin --uid USER_NAME --display-name "DISPLAY_NAME" --access_key USER_NAME --secret SECRET user create

    示例

    [user@rgw ~]$ radosgw-admin --uid TESTER --display-name "TestUser" --access_key TESTER --secret test123 user create

  2. 配置 Ceph 用户功能:

    语法

    radosgw-admin caps add --uid="USER_NAME" --caps="oidc-provider=*"

    示例

    [user@rgw ~]$ radosgw-admin caps add --uid="TESTER" --caps="oidc-provider=*"

  3. 使用 Secure Token Service(STS)API 在角色信任策略中添加条件:

    语法

    "{\"Version\":\"2020-01-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Federated\":[\"arn:aws:iam:::oidc-provider/IDP_URL\"]},\"Action\":[\"sts:AssumeRoleWithWebIdentity\"],\"Condition\":{\"StringEquals\":{\"IDP_URL:app_id\":\"AUD_FIELD\"\}\}\}\]\}"

    重要

    上述语法示例中的 app_id 必须与传入令牌的 AUD_FIELD 字段匹配。

其它资源

3.3.9.4. 获取 OpenID Connect 供应商的 thumbprint

要获得 OpenID Connect 供应商(IDP)配置文档。

先决条件

  • 安装 opensslcurl 软件包。

流程

  1. 从 IDP 的 URL 获取配置文档:

    语法

    curl -k -v \
         -X GET \
         -H "Content-Type: application/x-www-form-urlencoded" \
         "IDP_URL:8000/CONTEXT/realms/REALM/.well-known/openid-configuration" \
       | jq .

    示例

    [user@client ~]$ curl -k -v \
         -X GET \
         -H "Content-Type: application/x-www-form-urlencoded" \
         "http://www.example.com:8000/auth/realms/quickstart/.well-known/openid-configuration" \
       | jq .

  2. 获取 IDP 证书:

    语法

    curl -k -v \
         -X GET \
         -H "Content-Type: application/x-www-form-urlencoded" \
         "IDP_URL/CONTEXT/realms/REALM/protocol/openid-connect/certs" \
         | jq .

    示例

    [user@client ~]$ curl -k -v \
         -X GET \
         -H "Content-Type: application/x-www-form-urlencoded" \
         "http://www.example.com/auth/realms/quickstart/protocol/openid-connect/certs" \
         | jq .

  3. 复制上一命令中的"x5c"响应的结果,并将它粘贴到 certificate.crt 文件中。在结束时包含 --BEGIN CERTIFICATE-- 开始和 --END CERTIFICATE--
  4. 获取证书指纹:

    语法

    openssl x509 -in CERT_FILE -fingerprint -noout

    示例

    [user@client ~]$ openssl x509 -in certificate.crt -fingerprint -noout
    SHA1 Fingerprint=F7:D7:B3:51:5D:D0:D3:19:DD:21:9A:43:A9:EA:72:7A:D6:06:52:87

  5. 从 SHA1 指纹中删除所有冒号,并将其用作在 IAM 请求中创建 IDP 实体的输入。

其它资源

3.3.9.5. 在 Keystone 中配置和使用 STS Lite(技术预览)

同一命名空间中的 Amazon 安全令牌服务(STS)和 S3 API 共存。STS 选项可以和 Keystone 选项一起配置。

注意

S3 和 STS API 都可以使用 Ceph 对象网关中的同一端点来访问。

先决条件

  • Red Hat Ceph Storage 5.0 或更高版本。
  • 正在运行的 Ceph 对象网关.
  • 安装 Boto Python 模块,版本 3 或更高版本。
  • Ceph 管理器节点的 root 级别访问。
  • OpenStack 节点的用户级访问权限。

流程

  1. 为 Ceph 对象网关客户端设置以下配置选项:

    语法

    ceph config set RGW_CLIENT_NAME rgw_sts_key STS_KEY
    ceph config set RGW_CLIENT_NAME rgw_s3_auth_use_sts true

    rgw_sts_key 是用于加密或解密会话令牌的 STS 密钥,且正好为 16 十六进制字符。

    重要

    STS 密钥需要是字母数字。

    示例

    [root@mgr ~]# ceph config set client.rgw rgw_sts_key 7f8fd8dd4700mnop
    [root@mgr ~]# ceph config set client.rgw rgw_s3_auth_use_sts true

  2. 在 OpenStack 节点上生成 EC2 凭据:

    示例

    [user@osp ~]$ openstack ec2 credentials create
    
    +------------+--------------------------------------------------------+
    | Field      | Value                                                  |
    +------------+--------------------------------------------------------+
    | access     | b924dfc87d454d15896691182fdeb0ef                       |
    | links      | {u'self': u'http://192.168.0.15/identity/v3/users/     |
    |            | 40a7140e424f493d8165abc652dc731c/credentials/          |
    |            | OS-EC2/b924dfc87d454d15896691182fdeb0ef'}              |
    | project_id | c703801dccaf4a0aaa39bec8c481e25a                       |
    | secret     | 6a2142613c504c42a94ba2b82147dc28                       |
    | trust_id   | None                                                   |
    | user_id    | 40a7140e424f493d8165abc652dc731c                       |
    +------------+--------------------------------------------------------+

  3. 使用生成的凭证,通过 GetSessionToken API 来备份一组临时安全凭证:

    示例

    import boto3
    
    access_key = b924dfc87d454d15896691182fdeb0ef
    secret_key = 6a2142613c504c42a94ba2b82147dc28
    
    client = boto3.client('sts',
    aws_access_key_id=access_key,
    aws_secret_access_key=secret_key,
    endpoint_url=https://www.example.com/rgw,
    region_name='',
    )
    
    response = client.get_session_token(
        DurationSeconds=43200
    )

  4. 获取临时凭证可用于发出 S3 调用:

    示例

    s3client = boto3.client('s3',
      aws_access_key_id = response['Credentials']['AccessKeyId'],
      aws_secret_access_key = response['Credentials']['SecretAccessKey'],
      aws_session_token = response['Credentials']['SessionToken'],
      endpoint_url=https://www.example.com/s3,
      region_name='')
    
    bucket = s3client.create_bucket(Bucket='my-new-shiny-bucket')
    response = s3client.list_buckets()
    for bucket in response["Buckets"]:
      print "{name}\t{created}".format(
        name = bucket['Name'],
        created = bucket['CreationDate'],
      )

  5. 创建新的 S3Access 角色并配置策略。

    1. 使用管理 CAPS 为用户分配:

      语法

      radosgw-admin caps add --uid="USER" --caps="roles=*"

      示例

      [root@mgr ~]# radosgw-admin caps add --uid="gwadmin" --caps="roles=*"

    2. 创建 S3Access 角色:

      语法

      radosgw-admin role create --role-name=ROLE_NAME --path=PATH --assume-role-policy-doc=TRUST_POLICY_DOC

      示例

      [root@mgr ~]# radosgw-admin role create --role-name=S3Access --path=/application_abc/component_xyz/ --assume-role-policy-doc=\{\"Version\":\"2012-10-17\",\"Statement\":\[\{\"Effect\":\"Allow\",\"Principal\":\{\"AWS\":\[\"arn:aws:iam:::user/TESTER\"\]\},\"Action\":\[\"sts:AssumeRole\"\]\}\]\}

    3. 将权限策略附加到 S3Access 角色:

      语法

      radosgw-admin role-policy put --role-name=ROLE_NAME --policy-name=POLICY_NAME --policy-doc=PERMISSION_POLICY_DOC

      示例

      [root@mgr ~]# radosgw-admin role-policy put --role-name=S3Access --policy-name=Policy --policy-doc=\{\"Version\":\"2012-10-17\",\"Statement\":\[\{\"Effect\":\"Allow\",\"Action\":\[\"s3:*\"\],\"Resource\":\"arn:aws:s3:::example_bucket\"\}\]\}

    4. 现在,另一个用户可以假定 gwadmin 用户的角色。例如,gwuser 用户可以假定 gwadmin 用户权限。
    5. 记录假定用户的 access_keysecret_key 值。

      示例

      [root@mgr ~]# radosgw-admin user info --uid=gwuser | grep -A1 access_key

  6. 使用 AssumeRole API 调用,提供来自假定用户的 access_keysecret_key 值:

    示例

    import boto3
    
    access_key = 11BS02LGFB6AL6H1ADMW
    secret_key = vzCEkuryfn060dfee4fgQPqFrncKEIkh3ZcdOANY
    
    client = boto3.client('sts',
    aws_access_key_id=access_key,
    aws_secret_access_key=secret_key,
    endpoint_url=https://www.example.com/rgw,
    region_name='',
    )
    
    response = client.assume_role(
    RoleArn='arn:aws:iam:::role/application_abc/component_xyz/S3Access',
    RoleSessionName='Bob',
    DurationSeconds=3600
    )

    重要

    AssumeRole API 需要 S3Access 角色。

其它资源

  • 有关安装 Boto Python 模块的更多信息,请参阅 Red Hat Ceph Storage 对象网关指南中的 Test S3 访问 部分。
  • 如需更多信息,请参阅 Red Hat Ceph Storage Object Gateway 指南中的 创建用户 部分。

3.3.9.6. 围绕将 STS Lite 与 Keystone 搭配使用的限制(技术预览)

Keystone 的一个限制是它不支持安全令牌服务(STS)请求。请求中不包含另一个限制的有效负载哈希。要解决这两个限制,必须修改 Boto 身份验证代码。

先决条件

  • 正在运行的 Red Hat Ceph Storage 集群,版本 5.0 或更高版本。
  • 正在运行的 Ceph 对象网关.
  • 安装 Boto Python 模块,版本 3 或更高版本。

流程

  1. 打开并编辑 Boto 的 auth.py 文件。

    1. 将以下四行添加到代码块中:

      class SigV4Auth(BaseSigner):
        """
        Sign a request with Signature V4.
        """
        REQUIRES_REGION = True
      
        def __init__(self, credentials, service_name, region_name):
            self.credentials = credentials
            # We initialize these value here so the unit tests can have
            # valid values.  But these will get overriden in ``add_auth``
            # later for real requests.
            self._region_name = region_name
            if service_name == 'sts': 1
                self._service_name = 's3' 2
            else: 3
                self._service_name = service_name 4
    2. 将以下两行添加到代码块中:

      def _modify_request_before_signing(self, request):
              if 'Authorization' in request.headers:
                  del request.headers['Authorization']
              self._set_necessary_date_headers(request)
              if self.credentials.token:
                  if 'X-Amz-Security-Token' in request.headers:
                      del request.headers['X-Amz-Security-Token']
                  request.headers['X-Amz-Security-Token'] = self.credentials.token
      
              if not request.context.get('payload_signing_enabled', True):
                  if 'X-Amz-Content-SHA256' in request.headers:
                      del request.headers['X-Amz-Content-SHA256']
                  request.headers['X-Amz-Content-SHA256'] = UNSIGNED_PAYLOAD 1
              else: 2
                  request.headers['X-Amz-Content-SHA256'] = self.payload(request)

其它资源

  • 有关安装 Boto Python 模块的更多信息,请参阅 Red Hat Ceph Storage 对象网关指南中的 Test S3 访问 部分。
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.