

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 跨 AWS 帳戶存取 DAX
<a name="DAX.cross-account-access"></a>

假設有一個 DynamoDB Accelerator (DAX) 叢集在一個 AWS 帳戶 （帳戶 A) 中執行，而且 DAX 叢集需要從另一個 AWS 帳戶 （帳戶 B) 中的 Amazon Elastic Compute Cloud (Amazon EC2) 執行個體存取。在本教學課程中，您使用來自帳戶 B 的 IAM 角色在帳戶 B 中啟動 EC2 執行個體，然後使用 EC2 執行個體的臨時安全憑證來擔任帳戶 A 的 IAM 角色。最後，您使用在帳戶 A 中擔任 IAM 角色的臨時安全憑證，透過 Amazon VPC 對等互連對帳戶 A 中的 DAX 叢集進行應用程式呼叫。為了執行這些工作，您在兩個 AWS 帳戶中都需要具備系統管理存取權。

**重要**  
 DAX 叢集無法從其他帳戶存取 DynamoDB 資料表。

**Topics**
+ [

## 設定 IAM
](#DAX.cross-account-access.iam-setup)
+ [

## 設定 VPC
](#DAX.cross-account-access.vpc-setup)
+ [

## 修改 DAX 用戶端以允許跨帳戶存取權
](#DAX.cross-account-access.modify-client)

## 設定 IAM
<a name="DAX.cross-account-access.iam-setup"></a>

1. 使用下列內容建立名為 `AssumeDaxRoleTrust.json` 的文字檔案，這可讓 Amazon EC2 代表您工作。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {
                   "Service": "ec2.amazonaws.com"
               },
               "Action": "sts:AssumeRole"
           }
       ]
   }
   ```

------

1. 在帳戶 B 中，建立 Amazon EC2 可在啟動執行個體時使用的角色。

   ```
   aws iam create-role \
       --role-name AssumeDaxRole \
       --assume-role-policy-document file://AssumeDaxRoleTrust.json
   ```

1. 使用下列內容建立名為 `AssumeDaxRolePolicy.json` 的文字檔案，這會允許在帳戶 B 中的 EC2 執行個體上執行的程式碼擔任帳戶 A 中的 IAM 角色。將 *accountA* 取代為帳戶 A 的實際 ID。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "sts:AssumeRole",
               "Resource": "arn:aws:iam::111122223333:role/DaxCrossAccountRole"
           }
       ]
   }
   ```

------

1. 將該政策新增至您剛建立的角色。

   ```
   aws iam put-role-policy \
       --role-name AssumeDaxRole \
       --policy-name AssumeDaxRolePolicy \
       --policy-document file://AssumeDaxRolePolicy.json
   ```

1. 建立執行個體設定檔以允許執行個體使用該角色。

   ```
   aws iam create-instance-profile \
       --instance-profile-name AssumeDaxInstanceProfile
   ```

1. 將角色與執行個體設定檔建立關聯。

   ```
   aws iam add-role-to-instance-profile \
       --instance-profile-name AssumeDaxInstanceProfile \
       --role-name AssumeDaxRole
   ```

1. 使用下列內容建立名為 `DaxCrossAccountRoleTrust.json` 的文字檔案，這可讓帳戶 B 擔任帳戶 A 角色。將 *accountB* 取代為帳戶 B 的實際 ID。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {
                   "AWS": "arn:aws:iam::111122223333:role/AssumeDaxRole"
               },
               "Action": "sts:AssumeRole"
           }
       ]
   }
   ```

------

1. 在帳戶 A 中，建立帳戶 B 可以擔任的角色。

   ```
   aws iam create-role \
       --role-name DaxCrossAccountRole \
       --assume-role-policy-document file://DaxCrossAccountRoleTrust.json
   ```

1. 建立一個名為 `DaxCrossAccountPolicy.json` 的文字檔案以允許存取 DAX 叢集。將 *dax-cluster-arn* 取代為 DAX 叢集的正確 Amazon Resource Name (ARN)。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "dax:GetItem",
                   "dax:BatchGetItem",
                   "dax:Query",
                   "dax:Scan",
                   "dax:PutItem",
                   "dax:UpdateItem",
                   "dax:DeleteItem",
                   "dax:BatchWriteItem",
                   "dax:ConditionCheckItem"
               ],
               "Resource": "arn:aws:dax:us-east-1:111122223333:cache/dax-cluster-name"
           }
       ]
   }
   ```

------

1. 在帳戶 A 中，將政策新增至角色。

   ```
   aws iam put-role-policy \
       --role-name DaxCrossAccountRole \
       --policy-name DaxCrossAccountPolicy \
       --policy-document file://DaxCrossAccountPolicy.json
   ```

## 設定 VPC
<a name="DAX.cross-account-access.vpc-setup"></a>

1. 尋找帳戶 A DAX 叢集的子網路群組。將 *cluster-name* 取代為帳戶 B 必須存取的 DAX 叢集名稱。

   ```
   aws dax describe-clusters \
       --cluster-name cluster-name
       --query 'Clusters[0].SubnetGroup'
   ```

1. 使用該*子網路群組*尋找該叢集的 VPC。

   ```
   aws dax describe-subnet-groups \
       --subnet-group-name subnet-group \
       --query 'SubnetGroups[0].VpcId'
   ```

1. 使用該 *vpc-id* 尋找該 VPC 的 CIDR。

   ```
   aws ec2 describe-vpcs \
       --vpc vpc-id \
       --query 'Vpcs[0].CidrBlock'
   ```

1. 從帳戶 B，使用不同於上一個步驟中找到的 CIDR 的非重疊 CIDR 來建立 VPC。然後，建立至少一個子網路。您可以在 或 中使用 [VPC 建立精靈](https://docs.aws.amazon.com/vpc/latest/userguide/getting-started-ipv4.html#getting-started-create-vpc)[AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/ec2/create-vpc.html)。 AWS 管理主控台 

1. 從帳戶 B，請求與帳戶 A VPC 的對等連線，如[建立和接受 VPC 對等互連](https://docs.aws.amazon.com/vpc/latest/peering/create-vpc-peering-connection.html)中所述。從帳戶 A 接受連線。

1. 從帳戶 B 尋找新 VPC 的路由表。將 *vpc-id* 取代為您在帳戶 B 中建立的 VPC ID。

   ```
   aws ec2 describe-route-tables \
       --filters 'Name=vpc-id,Values=vpc-id' \
       --query 'RouteTables[0].RouteTableId'
   ```

1. 新增路由，將目的地為帳戶 A CIDR 的流量傳送至 VPC 對等互連。請記得將每個 *user input placeholder* 取代為您帳戶的正確值。

   ```
   aws ec2 create-route \
       --route-table-id accountB-route-table-id \
       --destination-cidr accountA-vpc-cidr \
       --vpc-peering-connection-id peering-connection-id
   ```

1. 使用您之前找到的 *vpc-id*，從帳戶 A 尋找 DAX 叢集的路由表。

   ```
   aws ec2 describe-route-tables \
       --filters 'Name=vpc-id, Values=accountA-vpc-id' \
       --query 'RouteTables[0].RouteTableId'
   ```

1. 從帳戶 A，新增路由，將目的地為帳戶 B CIDR 的流量傳送至 VPC 對等互連。使用您帳戶的正確值取代每個 *user input placeholder*。

   ```
   aws ec2 create-route \
       --route-table-id accountA-route-table-id \
       --destination-cidr accountB-vpc-cidr \
       --vpc-peering-connection-id peering-connection-id
   ```

1. 從帳戶 B，在先前建立的 VPC 中啟動 EC2 執行個體。將其命名為 `AssumeDaxInstanceProfile`。您可以使用 中的[啟動精靈](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/launching-instance.html) AWS 管理主控台 或 [AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/ec2/run-instances.html)。記下執行個體的安全群組。

1. 從帳戶 A 尋找 DAX 叢集所使用的安全群組。記得將 *cluster-name* 取代為您的 DAX 叢集名稱。

   ```
   aws dax describe-clusters \
       --cluster-name cluster-name \
       --query 'Clusters[0].SecurityGroups[0].SecurityGroupIdentifier'
   ```

1. 更新 DAX 叢集的安全群組，以允許來自您在帳戶 B 中建立之 EC2 執行個體的安全群組的傳入流量。請記得使用正確的帳戶值取代 *user input placeholders*。

   ```
   aws ec2 authorize-security-group-ingress \
       --group-id accountA-security-group-id \
       --protocol tcp \
       --port 8111 \
       --source-group accountB-security-group-id \
       --group-owner accountB-id
   ```

此時，帳戶 B 的 EC2 執行個體上的應用程式可以使用執行個體設定檔來擔任 `arn:aws:iam::accountA-id:role/DaxCrossAccountRole` 角色並使用 DAX 叢集。

## 修改 DAX 用戶端以允許跨帳戶存取權
<a name="DAX.cross-account-access.modify-client"></a>

**注意**  
AWS Security Token Service (AWS STS) 登入資料是臨時登入資料。某些用戶端會自動處理重新整理，而有些則需要額外的邏輯來重新整理憑證。我們建議您遵循適當說明文件的指引。

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

本節可協助您修改現有的 DAX 用戶端程式碼，以允許跨帳戶 DAX 存取。如果您還沒有 DAX 用戶端程式碼，可以在 [Java 與 DAX](DAX.client.run-application-java.md) 教學課程中找到可行的程式碼範例。

1. 新增以下匯入專案。

   ```
   import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
   import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
   import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
   ```

1. 從 取得登入資料提供者 AWS STS 並建立 DAX 用戶端物件。請記得將每個 *user input placeholder* 取代為您帳戶的正確值。

   ```
   AWSSecurityTokenService awsSecurityTokenService = AWSSecurityTokenServiceClientBuilder
        .standard()
        .withRegion(region)
        .build();
   
   STSAssumeRoleSessionCredentialsProvider credentials =  new STSAssumeRoleSessionCredentialsProvider.Builder("arn:aws:iam::accountA:role/RoleName", "TryDax")
        .withStsClient(awsSecurityTokenService)
        .build();
   
   DynamoDB client = AmazonDaxClientBuilder.standard()
       .withRegion(region)
       .withEndpointConfiguration(dax_endpoint)
       .withCredentials(credentials)
       .build();
   ```

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

本節可協助您修改現有的 DAX 用戶端程式碼，以允許跨帳戶 DAX 存取。如果您還沒有 DAX 用戶端程式碼，可以在 [.NET 和 DAX](DAX.client.run-application-dotnet.md) 教學課程中找到可行的程式碼範例。

1. 將 [AWSSDK.SecurityToken](https://www.nuget.org/packages/AWSSDK.SecurityToken) NuGet 套件新增到解決方案。

   ```
   <PackageReference Include="AWSSDK.SecurityToken" Version="latest version" />
   ```

1. 使用 `SecurityToken` 和 `SecurityToken.Model` 套件。

   ```
   using Amazon.SecurityToken;
   using Amazon.SecurityToken.Model;
   ```

1. 從 `AmazonSimpleTokenService` 取得臨時憑證並建立 `ClusterDaxClient` 物件。請記得將每個 *user input placeholder* 取代為您帳戶的正確值。

   ```
   IAmazonSecurityTokenService sts = new AmazonSecurityTokenServiceClient();
   
   var assumeRoleResponse = sts.AssumeRole(new AssumeRoleRequest
   {
       RoleArn = "arn:aws:iam::accountA:role/RoleName",
                   RoleSessionName = "TryDax"
   });
   
   Credentials credentials = assumeRoleResponse.Credentials;
   
   var clientConfig = new DaxClientConfig(dax_endpoint, port)
   {
       AwsCredentials = assumeRoleResponse.Credentials
                      
   };
   
   var client = new ClusterDaxClient(clientConfig);
   ```

------
#### [ Go ]

本節可協助您修改現有的 DAX 用戶端程式碼，以允許跨帳戶 DAX 存取。如果您還沒有 DAX 用戶端程式碼，可以[在 GitHub 上找到可行的程式碼範例](https://github.com/aws-samples/aws-dax-go-sample/blob/master/try_dax.go)。

1. 匯入 AWS STS 和 工作階段套件。

   ```
   import (
       "github.com/aws/aws-sdk-go/aws/session"
       "github.com/aws/aws-sdk-go/service/sts"
       "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
   )
   ```

1. 從 `AmazonSimpleTokenService` 取得臨時憑證並建立 DAX 用戶端物件。請記得將每個 *user input placeholder* 取代為您帳戶的正確值。

   ```
   sess, err := session.NewSession(&aws.Config{
       Region: aws.String(region)},
   )
   if err != nil {
       return nil, err
   }
   
   stsClient := sts.New(sess)
   arp := &stscreds.AssumeRoleProvider{
                   Duration:     900 * time.Second,
                   ExpiryWindow: 10 * time.Second,
                   RoleARN:      "arn:aws:iam::accountA:role/role_name",
                   Client:       stsClient,
                   RoleSessionName: "session_name",
           }cfg := dax.DefaultConfig()
   
   cfg.HostPorts = []string{dax_endpoint}
   cfg.Region = region
   cfg.Credentials = credentials.NewCredentials(arp)
   daxClient := dax.New(cfg)
   ```

------
#### [ Python ]

本節可協助您修改現有的 DAX 用戶端程式碼，以允許跨帳戶 DAX 存取。如果您還沒有 DAX 用戶端程式碼，可以在 [Python 和 DAX](DAX.client.run-application-python.md) 教學課程中找到可行的程式碼範例。

1. 匯入 `boto3`。

   ```
   import boto3
   ```

1. 從 `sts` 取得臨時憑證並建立 `AmazonDaxClient` 物件。請記得將每個 *user input placeholder* 取代為您帳戶的正確值。

   ```
   sts = boto3.client('sts')
   stsresponse = sts.assume_role(RoleArn='arn:aws:iam::accountA:role/RoleName',RoleSessionName='tryDax')
   credentials = botocore.session.get_session()['Credentials']
   
   dax = amazondax.AmazonDaxClient(session, region_name=region, endpoints=[dax_endpoint], aws_access_key_id=credentials['AccessKeyId'], aws_secret_access_key=credentials['SecretAccessKey'], aws_session_token=credentials['SessionToken'])
   client = dax
   ```

------
#### [ Node.js ]

本節可協助您修改現有的 DAX 用戶端程式碼，以允許跨帳戶 DAX 存取。如果您還沒有 DAX 用戶端程式碼，可以在 [Node.js 和 DAX](DAX.client.run-application-nodejs.md) 教學課程中找到可行的程式碼範例。請記得將每個 *user input placeholder* 取代為您帳戶的正確值。

```
const AmazonDaxClient = require('amazon-dax-client');
const AWS = require('aws-sdk');
const region = 'region';
const endpoints = [daxEndpoint1, ...];

const getCredentials = async() => {
  return new Promise((resolve, reject) => {
    const sts = new AWS.STS();
    const roleParams = {
      RoleArn: 'arn:aws:iam::accountA:role/RoleName',
      RoleSessionName: 'tryDax',
    };
    sts.assumeRole(roleParams, (err, session) => {
      if(err) {
        reject(err);
      } else {
        resolve({
          accessKeyId: session.Credentials.AccessKeyId,
          secretAccessKey: session.Credentials.SecretAccessKey,
          sessionToken: session.Credentials.SessionToken,
        });
      }
    });
  });
};

const createDaxClient = async() => {
  const credentials = await getCredentials();
  const daxClient = new AmazonDaxClient({endpoints: endpoints, region: region, accessKeyId: credentials.accessKeyId, secretAccessKey: credentials.secretAccessKey, sessionToken: credentials.sessionToken});
  return new AWS.DynamoDB.DocumentClient({service: daxClient});
};

createDaxClient().then((client) => {
  client.get(...);
  ...
}).catch((error) => {
  console.log('Caught an error: ' + error);
});
```

------