

# 使用联合身份用户临时凭证提出请求
<a name="AuthUsingTempFederationToken"></a>

您可以请求临时安全凭证并将它们提供给需要访问您的 Amazon 资源的联合身份用户或应用程序。本节提供了一些示例，介绍了如何使用 Amazon 开发工具包为联合身份用户或应用程序获取临时安全证书以及如何使用这些证书向 Amazon S3 发送经身份验证的请求。有关可用 Amazon 开发工具包的列表，请参阅 [示例代码和库](https://www.amazonaws.cn/code/)。

**注意**  
Amazon Web Services 账户 和 IAM 用户皆可请求适用于联合身份用户的临时安全证书。然而，为了提高安全性，只有具有所需许可的 IAM 用户才能请求这些临时证书，这样可确保联合用户能够从请求的 IAM 用户中获得最多的许可。在某些应用程序中，您可能会发现创建一个具有特定权限的 IAM 用户以专门用于向联合身份用户和应用程序授予临时安全凭证比较合适。

------
#### [ Java ]

您可以为联合身份用户和应用程序提供临时安全凭证，以便它们可以发送经身份验证的请求，从而访问您的 Amazon 资源。请求这些临时凭证时，必须提供用户名和 IAM 策略（描述要授予的资源权限）。默认情况下，会话的持续时间为一个小时。您可以在为联合身份用户和应用程序请求临时安全凭证时，显式地设置其他持续时间值。

**注意**  
为了提高请求适用于联合身份用户和应用程序的临时安全凭证时的安全性，建议使用仅具有所需访问权限的专用 IAM 用户。您创建的临时用户可获取的许可绝对不能超过请求临时安全证书的 IAM 用户的许可。有关更多信息，请参阅 [Amazon Identity and Access Management 常见问题](https://www.amazonaws.cn/iam/faqs/#What_are_the_best_practices_for_using_temporary_security_credentials)。

要提供安全凭证并发送经身份验证的请求以访问资源，请执行以下操作：
+ 创建 `AWSSecurityTokenServiceClient` 类的实例。
+ 通过调用安全令牌服务 (STS) 客户端的 `getFederationToken()` 方法启动会话。提供会话信息，包括要附加到临时凭证的用户名和 IAM 策略。您可以提供可选的会话持续时间。此方法将返回您的临时安全凭证。
+ 将临时安全凭证打包在 `BasicSessionCredentials` 对象的实例中。您可以使用此对象来向您的 Amazon S3 客户端提供临时安全凭证。
+ 使用临时安全凭证创建 `AmazonS3Client` 类的实例。您可以使用此客户端向 Amazon S3 发送请求。如果您使用过期的凭证发送请求，Amazon S3 将返回错误。

**Example**  
该示例列出了指定 S3 存储桶中的键。在该示例中，您将为联合身份用户的时长两个小时的会话获取临时安全凭证，然后使用这些凭证向 Amazon S3 发送经身份验证的请求。要运行该示例，您需要创建具有附加策略（允许用户请求临时安全凭证和列出 Amazon 资源）的 IAM 用户。以下策略将实现此操作：  

```
 1. {
 2.   "Statement":[{
 3.       "Action":["s3:ListBucket",
 4.         "sts:GetFederationToken*"
 5.       ],
 6.       "Effect":"Allow",
 7.       "Resource":"*"
 8.     }
 9.   ]
10. }
```
有关如何创建 IAM 用户的更多信息，请参阅《IAM 用户指南》**中的[创建您的第一个 IAM 用户和管理员组](https://docs.amazonaws.cn/IAM/latest/UserGuide/getting-started_create-admin-group.html)。  
创建 IAM 用户并附加上述策略之后，您可以运行以下示例。有关创建和测试有效示例的说明，请参阅《Amazon SDK for Java 开发人员指南》中的[入门](https://docs.amazonaws.cn/sdk-for-java/v1/developer-guide/getting-started.html)。  

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.auth.policy.Policy;
import com.amazonaws.auth.policy.Resource;
import com.amazonaws.auth.policy.Statement;
import com.amazonaws.auth.policy.Statement.Effect;
import com.amazonaws.auth.policy.actions.S3Actions;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.services.securitytoken.model.Credentials;
import com.amazonaws.services.securitytoken.model.GetFederationTokenRequest;
import com.amazonaws.services.securitytoken.model.GetFederationTokenResult;

import java.io.IOException;

public class MakingRequestsWithFederatedTempCredentials {

    public static void main(String[] args) throws IOException {
        Regions clientRegion = Regions.DEFAULT_REGION;
        String bucketName = "*** Specify bucket name ***";
        String federatedUser = "*** Federated user name ***";
        String resourceARN = "arn:aws:s3:::" + bucketName;

        try {
            AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder
                    .standard()
                    .withCredentials(new ProfileCredentialsProvider())
                    .withRegion(clientRegion)
                    .build();

            GetFederationTokenRequest getFederationTokenRequest = new GetFederationTokenRequest();
            getFederationTokenRequest.setDurationSeconds(7200);
            getFederationTokenRequest.setName(federatedUser);

            // Define the policy and add it to the request.
            Policy policy = new Policy();
            policy.withStatements(new Statement(Effect.Allow)
                    .withActions(S3Actions.ListObjects)
                    .withResources(new Resource(resourceARN)));
            getFederationTokenRequest.setPolicy(policy.toJson());

            // Get the temporary security credentials.
            GetFederationTokenResult federationTokenResult = stsClient.getFederationToken(getFederationTokenRequest);
            Credentials sessionCredentials = federationTokenResult.getCredentials();

            // Package the session credentials as a BasicSessionCredentials
            // object for an Amazon S3 client object to use.
            BasicSessionCredentials basicSessionCredentials = new BasicSessionCredentials(
                    sessionCredentials.getAccessKeyId(),
                    sessionCredentials.getSecretAccessKey(),
                    sessionCredentials.getSessionToken());
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(basicSessionCredentials))
                    .withRegion(clientRegion)
                    .build();

            // To verify that the client works, send a listObjects request using
            // the temporary security credentials.
            ObjectListing objects = s3Client.listObjects(bucketName);
            System.out.println("No. of Objects = " + objects.getObjectSummaries().size());
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
```

------
#### [ .NET ]

您可以为联合身份用户和应用程序提供临时安全凭证，以便它们可以发送经身份验证的请求，从而访问您的 Amazon 资源。请求这些临时凭证时，必须提供用户名和 IAM 策略（描述要授予的资源权限）。默认情况下，会话的持续时间为一个小时。您可以在为联合身份用户和应用程序请求临时安全凭证时，显式地设置其他持续时间值。有关发送经身份验证的请求的信息，请参阅[提出请求](MakingRequests.md)。

**注意**  
当请求适用于联合身份用户和应用程序的临时安全凭证时，为了提高安全性，建议使用仅具有所需访问权限的专用 IAM 用户。您创建的临时用户可获取的许可绝对不能超过请求临时安全证书的 IAM 用户的许可。有关更多信息，请参阅 [Amazon Identity and Access Management 常见问题](https://www.amazonaws.cn/iam/faqs/#What_are_the_best_practices_for_using_temporary_security_credentials)。

您应当执行以下操作：
+ 创建 Amazon Security Token Service客户端 `AmazonSecurityTokenServiceClient` 类的实例。
+ 通过调用 STS 客户端的 `GetFederationToken` 方法开始会话。您需要提供会话信息，包括要附加到临时凭证的用户名和 IAM 策略。（可选）您可以提供会话持续时间。此方法将返回您的临时安全凭证。
+ 将临时安全凭证打包在 `SessionAWSCredentials` 对象的实例中。您可以使用此对象来向您的 Amazon S3 客户端提供临时安全凭证。
+ 通过传递临时安全凭证创建 `AmazonS3Client` 类的实例。您可使用此客户端向 Amazon S3 发送请求。如果您使用过期的凭证发送请求，Amazon S3 将返回错误。

**Example**  
以下 C\# 示例列出了指定存储桶中的密钥。在此示例中，将为联合身份用户 (User1) 的时长两个小时的会话获取临时安全凭证，然后使用这些凭证向 Amazon S3 发送经身份验证的请求。  
+ 在此练习中，您将创建具有最低权限的 IAM 用户。通过使用此 IAM 用户的凭证，可为其他用户请求临时凭证。此示例仅列出特定存储桶中的对象。创建附加了以下策略的 IAM 用户：

  ```
   1. {
   2.   "Statement":[{
   3.       "Action":["s3:ListBucket",
   4.         "sts:GetFederationToken*"
   5.       ],
   6.       "Effect":"Allow",
   7.       "Resource":"*"
   8.     }
   9.   ]
  10. }
  ```

  该策略允许 IAM 用户请求临时安全凭证和用于仅列出 Amazon 资源的访问权限。有关如何创建 IAM 用户的更多信息，请参阅《IAM 用户指南》**中的[创建您的 IAM 用户和管理员组](https://docs.amazonaws.cn/IAM/latest/UserGuide/getting-started_create-admin-group.html)。
+ 使用 IAM 用户安全凭证测试以下示例。该示例将使用临时安全证书向 Amazon S3 发送经身份验证的请求。该示例在为联合身份用户 (User1) 请求临时安全凭证时指定了以下策略，该策略对列出特定存储桶 (`YourBucketName`) 中的对象设置了访问权限限制。您必须更新策略并提供您自己的现有存储桶名称。

  ```
   1. {
   2.   "Statement":[
   3.     {
   4.       "Sid":"1",
   5.       "Action":["s3:ListBucket"],
   6.       "Effect":"Allow", 
   7.       "Resource":"arn:aws:s3:::YourBucketName"
   8.     }
   9.   ]
  10. }
  ```
+   
**Example**  

  更新以下示例并提供在前面的联合身份用户访问策略中指定的存储桶名称。有关设置和运行代码示例的信息，请参阅《适用于 .NET 的 Amazon SDK 开发人员指南》**中的[适用于 .NET 的 Amazon SDK 入门](https://docs.amazonaws.cn/sdk-for-net/latest/developer-guide/net-dg-setup.html)。

  ```
  using Amazon;
  using Amazon.Runtime;
  using Amazon.S3;
  using Amazon.S3.Model;
  using Amazon.SecurityToken;
  using Amazon.SecurityToken.Model;
  using System;
  using System.Collections.Generic;
  using System.Threading.Tasks;
  
  namespace Amazon.DocSamples.S3
  {
      class TempFederatedCredentialsTest
      {
          private const string bucketName = "*** bucket name ***";
          // Specify your bucket region (an example region is shown).
          private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
          private static IAmazonS3 client;
  
          public static void Main()
          {
              ListObjectsAsync().Wait();
          }
  
          private static async Task ListObjectsAsync()
          {
              try
              {
                  Console.WriteLine("Listing objects stored in a bucket");
                  // Credentials use the default AWS SDK for .NET credential search chain. 
                  // On local development machines, this is your default profile.
                  SessionAWSCredentials tempCredentials =
                      await GetTemporaryFederatedCredentialsAsync();
  
                  // Create a client by providing temporary security credentials.
                  using (client = new AmazonS3Client(bucketRegion))
                  {
                      ListObjectsRequest listObjectRequest = new ListObjectsRequest();
                      listObjectRequest.BucketName = bucketName;
  
                      ListObjectsResponse response = await client.ListObjectsAsync(listObjectRequest);
                      List<S3Object> objects = response.S3Objects;
                      Console.WriteLine("Object count = {0}", objects.Count);
  
                      Console.WriteLine("Press any key to continue...");
                      Console.ReadKey();
                  }
              }
              catch (AmazonS3Exception e)
              {
                  Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message);
              }
              catch (Exception e)
              {
                  Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
              }
          }
  
          private static async Task<SessionAWSCredentials> GetTemporaryFederatedCredentialsAsync()
          {
              AmazonSecurityTokenServiceConfig config = new AmazonSecurityTokenServiceConfig();
              AmazonSecurityTokenServiceClient stsClient =
                  new AmazonSecurityTokenServiceClient(
                                               config);
  
              GetFederationTokenRequest federationTokenRequest =
                                       new GetFederationTokenRequest();
              federationTokenRequest.DurationSeconds = 7200;
              federationTokenRequest.Name = "User1";
              federationTokenRequest.Policy = @"{
                 ""Statement"":
                 [
                   {
                     ""Sid"":""Stmt1311212314284"",
                     ""Action"":[""s3:ListBucket""],
                     ""Effect"":""Allow"",
                     ""Resource"":""arn:aws:s3:::" + bucketName + @"""
                    }
                 ]
               }
              ";
  
              GetFederationTokenResponse federationTokenResponse =
                          await stsClient.GetFederationTokenAsync(federationTokenRequest);
              Credentials credentials = federationTokenResponse.Credentials;
  
              SessionAWSCredentials sessionCredentials =
                  new SessionAWSCredentials(credentials.AccessKeyId,
                                            credentials.SecretAccessKey,
                                            credentials.SessionToken);
              return sessionCredentials;
          }
      }
  }
  ```

------
#### [ PHP ]

本主题介绍如何使用 适用于 PHP 的 Amazon SDK 的版本 3 中的类请求适用于联合身份用户和应用程序的临时安全凭证，并使用这些凭证访问 Amazon S3 中存储的资源。有关适用于 Ruby 的 Amazon 开发工具包 API 的更多信息，请转到[适用于 Ruby 的 Amazon 开发工具包 – 版本 2](https://docs.amazonaws.cn/sdkforruby/api/index.html)。

您可以为联合身份用户和应用程序提供临时安全凭证，以便它们可以发送经身份验证的请求，从而访问您的 Amazon 资源。请求这些临时凭证时，必须提供用户名和 IAM 策略（描述要授予的资源权限）。当会话持续时间过期时，这些凭证将过期。默认情况下，会话的持续时间为一个小时。可以在请求适用于联合身份用户和应用程序的临时安全凭证时为持续时间显式设置不同的值。有关临时安全凭证的更多信息，请参阅《IAM 用户指南》**中的[临时安全凭证](https://docs.amazonaws.cn/IAM/latest/UserGuide/id_credentials_temp.html)。有关向联合身份用户和应用程序提供临时安全凭证的信息，请参阅[提出请求](MakingRequests.md)。

为了提高请求适用于联合身份用户和应用程序的临时安全凭证时的安全性，建议使用仅具有所需访问权限的专用 IAM 用户。您创建的临时用户可获取的许可绝对不能超过请求临时安全证书的 IAM 用户的许可。有关联合身份的更多信息，亲参阅 [Amazon Identity and Access Management 常见问题](https://www.amazonaws.cn/iam/faqs/#What_are_the_best_practices_for_using_temporary_security_credentials)。

有关适用于 Ruby 的 Amazon 开发工具包 API 的更多信息，请转到[适用于 Ruby 的 Amazon 开发工具包 – 版本 2](https://docs.amazonaws.cn/sdkforruby/api/index.html)。

**Example**  
以下 PHP 示例列出了指定存储桶中的密钥。在此示例中，您将获取联合身份用户 (User1) 的时长一小时的会话的临时安全凭证。然后，您使用临时安全凭证向 Amazon S3 发送经身份验证的请求。  
为了提高请求适用于其他人的临时凭证时的安全性，请使用具有请求临时安全凭证的权限的 IAM 用户的安全凭证。要确保 IAM 用户仅向联合身份用户授予特定于应用程序的最低权限，还可以限制此 IAM 用户的访问权限。此示例仅列出特定存储桶中的对象。创建附加了以下策略的 IAM 用户：  

```
 1. {
 2.   "Statement":[{
 3.       "Action":["s3:ListBucket",
 4.         "sts:GetFederationToken*"
 5.       ],
 6.       "Effect":"Allow",
 7.       "Resource":"*"
 8.     }
 9.   ]
10. }
```
该策略允许 IAM 用户请求临时安全凭证和用于仅列出 Amazon 资源的访问权限。有关如何创建 IAM 用户的更多信息，请参阅《IAM 用户指南》**中的[创建您的第一个 IAM 用户和管理员组](https://docs.amazonaws.cn/IAM/latest/UserGuide/getting-started_create-admin-group.html)。  
您现在可以使用 IAM 用户安全证书测试下面的示例。该示例将使用临时安全凭证向 Amazon S3 发送经身份验证的请求。为联合身份用户 (User1) 请求临时安全凭证时，此示例指定了以下策略，该策略将访问权限限制为列出特定存储桶中的对象。请使用存储桶名称更新该策略。  

```
 1. {
 2.   "Statement":[
 3.     {
 4.       "Sid":"1",
 5.       "Action":["s3:ListBucket"],
 6.       "Effect":"Allow", 
 7.       "Resource":"arn:aws:s3:::{{YourBucketName}}"
 8.     }
 9.   ]
10. }
```
在以下示例中，当指定策略资源时，请将 `YourBucketName` 替换为您的存储桶的名称：  

```
 require 'vendor/autoload.php';

use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;
use Aws\Sts\StsClient;

$bucket = '*** Your Bucket Name ***';

// In real applications, the following code is part of your trusted code. It has
// the security credentials that you use to obtain temporary security credentials.
$sts = new StsClient([
    'version' => 'latest',
    'region' => 'us-east-1'
]);

// Fetch the federated credentials.
$sessionToken = $sts->getFederationToken([
    'Name'              => 'User1',
    'DurationSeconds'    => '3600',
    'Policy'            => json_encode([
        'Statement' => [
            'Sid'              => 'randomstatementid' . time(),
            'Action'           => ['s3:ListBucket'],
            'Effect'           => 'Allow',
            'Resource'         => 'arn:aws:s3:::' . $bucket
        ]
    ])
]);

// The following will be part of your less trusted code. You provide temporary
// security credentials so the code can send authenticated requests to Amazon S3.

$s3 = new S3Client([
    'region' => 'us-east-1',
    'version' => 'latest',
    'credentials' => [
        'key' => $sessionToken['Credentials']['AccessKeyId'],
        'secret' => $sessionToken['Credentials']['SecretAccessKey'],
        'token' => $sessionToken['Credentials']['SessionToken']
    ]
]);

try {
    $result = $s3->listObjects([
        'Bucket' => $bucket
    ]);
} catch (S3Exception $e) {
    echo $e->getMessage() . PHP_EOL;
}
```

------
#### [ Ruby ]

您可以为联合身份用户和应用程序提供临时安全凭证，以便它们可以发送经身份验证的请求，从而访问您的 Amazon 资源。从 IAM 服务请求临时凭证时，您必须提供用户名和 IAM 策略（描述您需要授予的资源权限）。默认情况下，会话的持续时间为一个小时。但是，如果您使用 IAM 用户证书来请求临时证书，您可以在为联合用户和应用程序请求临时安全证书时，显式地设置其他持续时间。有关适用于联合身份用户和应用程序的临时安全凭证的信息，请参阅[提出请求](MakingRequests.md)。

**注意**  
为了提高请求适用于联合身份用户和应用程序的临时安全凭证时的安全性，您可能需要使用仅具有所需访问权限的专用 IAM 用户。您创建的临时用户可获取的许可绝对不能超过请求临时安全证书的 IAM 用户的许可。有关更多信息，请参阅 [Amazon Identity and Access Management 常见问题](https://www.amazonaws.cn/iam/faqs/#What_are_the_best_practices_for_using_temporary_security_credentials)。

**Example**  
以下 Ruby 代码示例允许具有一组有限权限的联合身份用户列出指定存储桶中的键。  

```
# Prerequisites:
#  - An existing Amazon S3 bucket.

require 'aws-sdk-s3'
require 'aws-sdk-iam'
require 'json'

# Checks to see whether a user exists in IAM; otherwise,
# creates the user.
#
# @param iam [Aws::IAM::Client] An initialized IAM client.
# @param user_name [String] The user's name.
# @return [Aws::IAM::Types::User] The existing or new user.
# @example
#   iam = Aws::IAM::Client.new(region: 'us-west-2')
#   user = get_user(iam, 'my-user')
#   exit 1 unless user.user_name
#   puts "User's name: #{user.user_name}"
def get_user(iam, user_name)
  puts "Checking for a user with the name '#{user_name}'..."
  response = iam.get_user(user_name: user_name)
  puts "A user with the name '#{user_name}' already exists."
  response.user
# If the user doesn't exist, create them.
rescue Aws::IAM::Errors::NoSuchEntity
  puts "A user with the name '#{user_name}' doesn't exist. Creating this user..."
  response = iam.create_user(user_name: user_name)
  iam.wait_until(:user_exists, user_name: user_name)
  puts "Created user with the name '#{user_name}'."
  response.user
rescue StandardError => e
  puts "Error while accessing or creating the user named '#{user_name}': #{e.message}"
end

# Gets temporary AWS credentials for an IAM user with the specified permissions.
#
# @param sts [Aws::STS::Client] An initialized AWS STS client.
# @param duration_seconds [Integer] The number of seconds for valid credentials.
# @param user_name [String] The user's name.
# @param policy [Hash] The access policy.
# @return [Aws::STS::Types::Credentials] AWS credentials for API authentication.
# @example
#   sts = Aws::STS::Client.new(region: 'us-west-2')
#   credentials = get_temporary_credentials(sts, duration_seconds, user_name,
#     {
#       'Version' => '2012-10-17',
#       'Statement' => [
#         'Sid' => 'Stmt1',
#         'Effect' => 'Allow',
#         'Action' => 's3:ListBucket',
#         'Resource' => 'arn:aws:s3:::amzn-s3-demo-bucket'
#       ]
#     }
#   )
#   exit 1 unless credentials.access_key_id
#   puts "Access key ID: #{credentials.access_key_id}"
def get_temporary_credentials(sts, duration_seconds, user_name, policy)
  response = sts.get_federation_token(
    duration_seconds: duration_seconds,
    name: user_name,
    policy: policy.to_json
  )
  response.credentials
rescue StandardError => e
  puts "Error while getting federation token: #{e.message}"
end

# Lists the keys and ETags for the objects in an Amazon S3 bucket.
#
# @param s3_client [Aws::S3::Client] An initialized Amazon S3 client.
# @param bucket_name [String] The bucket's name.
# @return [Boolean] true if the objects were listed; otherwise, false.
# @example
#   s3_client = Aws::S3::Client.new(region: 'us-west-2')
#   exit 1 unless list_objects_in_bucket?(s3_client, 'amzn-s3-demo-bucket')
def list_objects_in_bucket?(s3_client, bucket_name)
  puts "Accessing the contents of the bucket named '#{bucket_name}'..."
  response = s3_client.list_objects_v2(
    bucket: bucket_name,
    max_keys: 50
  )

  if response.count.positive?
    puts "Contents of the bucket named '#{bucket_name}' (first 50 objects):"
    puts 'Name => ETag'
    response.contents.each do |obj|
      puts "#{obj.key} => #{obj.etag}"
    end
  else
    puts "No objects in the bucket named '#{bucket_name}'."
  end
  true
rescue StandardError => e
  puts "Error while accessing the bucket named '#{bucket_name}': #{e.message}"
end

# Example usage:
def run_me
  region = "us-west-2"
  user_name = "my-user"
  bucket_name = "amzn-s3-demo-bucket"

  iam = Aws::IAM::Client.new(region: region)
  user = get_user(iam, user_name)

  exit 1 unless user.user_name

  puts "User's name: #{user.user_name}"
  sts = Aws::STS::Client.new(region: region)
  credentials = get_temporary_credentials(sts, 3600, user_name,
                                          {
                                            'Version' => '2012-10-17',
                                            'Statement' => [
                                              'Sid' => 'Stmt1',
                                              'Effect' => 'Allow',
                                              'Action' => 's3:ListBucket',
                                              'Resource' => "arn:aws:s3:::#{bucket_name}"
                                            ]
                                          })

  exit 1 unless credentials.access_key_id

  puts "Access key ID: #{credentials.access_key_id}"
  s3_client = Aws::S3::Client.new(region: region, credentials: credentials)

  exit 1 unless list_objects_in_bucket?(s3_client, bucket_name)
end

run_me if $PROGRAM_NAME == __FILE__
```

------