

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# VPC Lattice 서비스에 대한 액세스 관리
<a name="access-management-overview"></a>

VPC Lattice는 기본적으로 안전합니다. 액세스 권한을 제공할 서비스 및 리소스 구성과 VPCs에 대한 액세스를 명시적으로 지정해야 하기 때문입니다. VPC 연결 또는 서비스 네트워크 유형의 VPC 엔드포인트를 통해 서비스에 액세스할 수 있습니다. 다중 계정 시나리오의 경우 [AWS Resource Access Manager](sharing.md)를 사용하여 계정 경계에서 서비스, 리소스 구성 및 서비스 네트워크를 공유할 수 있습니다.

 VPC Lattice는 네트워크의 여러 계층에서 defense-in-depth 전략을 구현할 수 있는 프레임워크를 제공합니다.
+ **첫 번째 계층** - 서비스 네트워크와의 서비스, 리소스, VPC 및 VPC 엔드포인트 연결입니다. VPC는 연결을 통해 또는 VPC 엔드포인트를 통해 서비스 네트워크에 연결될 수 있습니다. VPC가 서비스 네트워크에 연결되지 않은 경우 VPC의 클라이언트는 서비스 네트워크와 연결된 서비스 및 리소스 구성에 액세스할 수 없습니다.
+ **두 번째 계층** – 서비스 네트워크를 위한 선택적인 네트워크 수준 보안 보호(예: 보안 그룹 및 네트워크 ACL). 이를 사용하면 VPC의 모든 클라이언트 대신 VPC의 특정 클라이언트 그룹에 대한 액세스를 허용할 수 있습니다.
+ **세 번째 계층** – 선택적인 VPC Lattice 인증 정책. 인증 정책을 서비스 네트워크 및 개별 서비스에 적용할 수 있습니다. 일반적으로 서비스 네트워크의 인증 정책은 네트워크 또는 클라우드 관리자가 운영하며 세분화되지 않은 인증을 구현합니다. AWS Organizations에 있는 특정 조직의 인증된 요청만 허용하는 경우를 예로 들 수 있습니다. 서비스 수준의 인증 정책의 경우 일반적으로 서비스 소유자가 세분화된 제어를 설정하는데, 이는 서비스 네트워크 수준에서 적용되는 세분화되지 않은 권한 부여보다 더 제한적일 수 있습니다.
**참고**  
서비스 네트워크의 인증 정책은 서비스 네트워크의 리소스 구성에는 적용되지 않습니다.

**액세스 제어 방법**
+ [인증 정책](auth-policies.md)
+ [보안 그룹](security-groups.md)
+ [네트워크 ACL](network-acls.md)

# 인증 정책을 사용하여 VPC Lattice 서비스에 대한 액세스 제어
<a name="auth-policies"></a>

VPC Lattice 인증 정책은 서비스 네트워크 또는 서비스에 연결하여 지정된 보안 주체가 서비스 그룹 또는 특정 서비스에 액세스할 수 있는지 여부를 제어하는 IAM 정책 문서입니다. 액세스를 제어하려는 각 서비스 네트워크 또는 서비스에 하나의 인증 정책을 연결할 수 있습니다.

**참고**  
서비스 네트워크의 인증 정책은 서비스 네트워크의 리소스 구성에는 적용되지 않습니다.

인증 정책은 IAM 자격 증명 기반 정책과 다릅니다. IAM 자격 증명 기반 정책은 IAM 엔터티(사용자, 그룹 또는 역할)에 연결되어 이들 엔터티가 어떤 리소스에 대해 어떤 조치를 취할 수 있는지 정의합니다. 인증 정책은 서비스 및 서비스 네트워크에 연결됩니다. 승인이 성공하려면 인증 정책과 ID 기반 정책 모두에 명시적 허용 문이 있어야 합니다. 자세한 내용은 [권한 부여의 작동 방식](#auth-policies-evaluation-logic) 단원을 참조하십시오.

 AWS CLI 및 콘솔을 사용하여 서비스 및 서비스 네트워크에 대한 인증 정책을 확인, 추가, 업데이트 또는 제거할 수 있습니다. 인증 정책을 추가, 업데이트 또는 제거할 때 준비하는 데 몇 분 정도 걸릴 수 있습니다. 를 사용할 때 올바른 리전에 있는지 AWS CLI확인합니다. 프로필의 기본 리전을 변경하거나 명령과 함께 `--region` 파라미터를 사용할 수 있습니다.

**Topics**
+ [인증 정책의 공통 요소](#auth-policies-common-elements)
+ [인증 정책의 리소스 형식](#auth-policies-resource-format)
+ [인증 정책에 사용할 수 있는 조건 키](#auth-policies-condition-keys)
+ [리소스 태그](#resource-tags)
+ [보안 주체 태그](#principal-tags)
+ [익명의(인증되지 않은) 보안 주체](#anonymous-unauthenticated-principals)
+ [인증 정책 예시](#example-auth-policies)
+ [권한 부여의 작동 방식](#auth-policies-evaluation-logic)

인증 정책을 시작하려면 절차에 따라 서비스 네트워크에 적용되는 인증 정책을 만드세요. 다른 서비스에 적용하지 않으려는 보다 제한적인 권한을 원하는 경우 개별 서비스에 인증 정책을 설정할 수 있습니다.

## 인증 정책으로 서비스 네트워크에 대한 액세스 관리
<a name="manage-access-to-service-networks"></a>

다음 AWS CLI 작업은 인증 정책을 사용하여 서비스 네트워크에 대한 액세스를 관리하는 방법을 보여줍니다. 콘솔 사용 지침은 [VPC Lattice의 서비스 네트워크](service-networks.md) 섹션을 참조하세요.

**Topics**
+ [서비스 네트워크에 인증 정책 추가](#add-service-network-auth-policy)
+ [서비스 네트워크의 인증 유형 변경](#change-service-network-auth-type)
+ [서비스 네트워크에서 인증 정책 제거](#remove-service-network-auth-policy)

### 서비스 네트워크에 인증 정책 추가
<a name="add-service-network-auth-policy"></a>

이 섹션의 단계에 따라를 사용하여 다음을 AWS CLI 수행합니다.
+ IAM을 사용하여 서비스 네트워크에 대한 액세스 제어를 활성화합니다.
+ 서비스 네트워크에 인증 정책을 추가합니다. 인증 정책을 추가하지 않으면 모든 트래픽에 액세스 거부 오류가 발생합니다.

**액세스 제어를 활성화하고 새 서비스 네트워크에 인증 정책을 추가하는 방법**

1. 인증 정책을 사용할 수 있도록 서비스 네트워크에 대한 액세스 제어를 활성화하려면 `--auth-type` 옵션과 값이 `AWS_IAM`인 **create-service-network** 명령을 사용합니다.

   ```
   aws vpc-lattice create-service-network --name Name --auth-type AWS_IAM [--tags TagSpecification]
   ```

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "arn": "arn",
      "authType": "AWS_IAM",
      "id": "sn-0123456789abcdef0",
      "name": "Name"
   }
   ```

1. **put-auth-policy** 명령을 사용하여 인증 정책을 추가할 서비스 네트워크의 ID와 추가할 인증 정책을 지정합니다.

   예를 들어, 다음 명령을 사용하여 ID가 *`sn-0123456789abcdef0`*인 서비스 네트워크에 대한 인증 정책을 생성합니다.

   ```
   aws vpc-lattice put-auth-policy --resource-identifier sn-0123456789abcdef0 --policy file://policy.json
   ```

   JSON을 사용하여 정책 정의를 생성합니다. 자세한 내용은 [인증 정책의 공통 요소](#auth-policies-common-elements) 단원을 참조하십시오.

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "policy": "policy",
      "state": "Active"
   }
   ```

**액세스 제어를 활성화하고 기존 서비스 네트워크에 인증 정책을 추가하는 방법**

1. 인증 정책을 사용할 수 있도록 서비스 네트워크에 대한 액세스 제어를 활성화하려면 `--auth-type` 옵션과 값이 `AWS_IAM`인 **update-service-network** 명령을 사용합니다.

   ```
   aws vpc-lattice update-service-network --service-network-identifier sn-0123456789abcdef0 --auth-type AWS_IAM
   ```

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "arn": "arn",
      "authType": "AWS_IAM",
      "id": "sn-0123456789abcdef0",
      "name": "Name"
   }
   ```

1. **put-auth-policy** 명령을 사용하여 인증 정책을 추가할 서비스 네트워크의 ID와 추가할 인증 정책을 지정합니다.

   ```
   aws vpc-lattice put-auth-policy --resource-identifier sn-0123456789abcdef0 --policy file://policy.json
   ```

   JSON을 사용하여 정책 정의를 생성합니다. 자세한 내용은 [인증 정책의 공통 요소](#auth-policies-common-elements) 단원을 참조하십시오.

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "policy": "policy",
      "state": "Active"
   }
   ```

### 서비스 네트워크의 인증 유형 변경
<a name="change-service-network-auth-type"></a>

**서비스 네트워크에 대한 인증 정책을 비활성화하는 방법**  
`--auth-type` 옵션과 값이 `NONE`인 **update-service-network** 명령을 사용합니다.

```
aws vpc-lattice update-service-network --service-network-identifier sn-0123456789abcdef0 --auth-type NONE
```

나중에 인증 정책을 다시 활성화해야 하는 경우 `--auth-type` 옵션에 `AWS_IAM`이 지정된 상태로 이 명령을 실행하세요.

### 서비스 네트워크에서 인증 정책 제거
<a name="remove-service-network-auth-policy"></a>

**서비스 네트워크에서 인증 정책을 제거하는 방법**  
**delete-auth-policy** 명령을 사용합니다.

```
aws vpc-lattice delete-auth-policy --resource-identifier sn-0123456789abcdef0
```

서비스 네트워크의 인증 유형을 `NONE`으로 변경하기 전에 인증 정책을 제거하면 요청이 실패합니다.

## 인증 정책으로 서비스에 대한 액세스 관리
<a name="manage-access-to-services"></a>

다음 AWS CLI 작업은 인증 정책을 사용하여 서비스에 대한 액세스를 관리하는 방법을 보여줍니다. 콘솔 사용 지침은 [VPC Lattice 내 서비스](services.md) 섹션을 참조하세요.

**Topics**
+ [서비스에 인증 정책 추가](#add-service-auth-policy)
+ [서비스의 인증 유형 변경](#change-service-auth-type)
+ [서비스에서 인증 정책 제거](#remove-service-auth-policy)

### 서비스에 인증 정책 추가
<a name="add-service-auth-policy"></a>

다음 단계에 따라를 사용하여 다음을 AWS CLI 수행합니다.
+ IAM을 사용하여 서비스에 대한 액세스 제어를 활성화합니다.
+ 서비스에 인증 정책을 추가합니다. 인증 정책을 추가하지 않으면 모든 트래픽에 액세스 거부 오류가 발생합니다.

**액세스 제어를 활성화하고 새 서비스에 인증 정책을 추가하는 방법**

1. 인증 정책을 사용할 수 있도록 서비스에 대한 액세스 제어를 활성화하려면 `--auth-type` 옵션과 값이 `AWS_IAM`인 **create-service** 명령을 사용합니다.

   ```
   aws vpc-lattice create-service --name Name --auth-type AWS_IAM [--tags TagSpecification]
   ```

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "arn": "arn",
      "authType": "AWS_IAM",
      "dnsEntry": { 
         ...
      },
      "id": "svc-0123456789abcdef0",
      "name": "Name",
      "status": "CREATE_IN_PROGRESS"
   }
   ```

1. **put-auth-policy** 명령을 사용하여 인증 정책을 추가할 서비스의 ID와 추가할 인증 정책을 지정합니다.

   예를 들어, 다음 명령을 사용하여 ID가 *svc-0123456789abcdef0*인 서비스에 대한 인증 정책을 생성합니다.

   ```
   aws vpc-lattice put-auth-policy --resource-identifier svc-0123456789abcdef0 --policy file://policy.json
   ```

   JSON을 사용하여 정책 정의를 생성합니다. 자세한 내용은 [인증 정책의 공통 요소](#auth-policies-common-elements) 단원을 참조하십시오.

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "policy": "policy",
      "state": "Active"
   }
   ```

**액세스 제어를 활성화하고 기존 서비스에 인증 정책을 추가하는 방법**

1. 인증 정책을 사용할 수 있도록 서비스에 대한 액세스 제어를 활성화하려면 `--auth-type` 옵션과 값이 `AWS_IAM`인 **update-service** 명령을 사용합니다.

   ```
   aws vpc-lattice update-service --service-identifier svc-0123456789abcdef0 --auth-type AWS_IAM
   ```

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "arn": "arn",
      "authType": "AWS_IAM",
      "id": "svc-0123456789abcdef0",
      "name": "Name"
   }
   ```

1. **put-auth-policy** 명령을 사용하여 인증 정책을 추가할 서비스의 ID와 추가할 인증 정책을 지정합니다.

   ```
   aws vpc-lattice put-auth-policy --resource-identifier svc-0123456789abcdef0 --policy file://policy.json
   ```

   JSON을 사용하여 정책 정의를 생성합니다. 자세한 내용은 [인증 정책의 공통 요소](#auth-policies-common-elements) 단원을 참조하십시오.

   이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

   ```
   {
      "policy": "policy",
      "state": "Active"
   }
   ```

### 서비스의 인증 유형 변경
<a name="change-service-auth-type"></a>

**서비스에 대한 인증 정책을 비활성화하는 방법**  
`--auth-type` 옵션과 값이 `NONE`인 **update-service** 명령을 사용합니다.

```
aws vpc-lattice update-service --service-identifier svc-0123456789abcdef0 --auth-type NONE
```

나중에 인증 정책을 다시 활성화해야 하는 경우 `--auth-type` 옵션에 `AWS_IAM`이 지정된 상태로 이 명령을 실행하세요.

### 서비스에서 인증 정책 제거
<a name="remove-service-auth-policy"></a>

**서비스에서 인증 정책을 제거하는 방법**  
**delete-auth-policy** 명령을 사용합니다.

```
aws vpc-lattice delete-auth-policy --resource-identifier svc-0123456789abcdef0
```

서비스의 인증 유형을 `NONE`으로 변경하기 전에 인증 정책을 제거하면 요청이 실패합니다.

서비스에 대한 인증된 요청을 요구하는 인증 정책을 활성화하는 경우 해당 서비스에 대한 모든 요청에는 Signature Version 4(SigV4)를 사용하여 계산된 유효한 요청 서명이 포함되어야 합니다. 자세한 내용은 [Amazon VPC Lattice에 대한 SIGv4 인증 요청](sigv4-authenticated-requests.md) 단원을 참조하십시오.

## 인증 정책의 공통 요소
<a name="auth-policies-common-elements"></a>

IAM 정책과 동일한 구문을 사용하여 VPC Lattice 인증 정책이 지정됩니다. 자세한 내용은 *IAM 사용 설명서*의 [자격 증명 기반 정책 및 리소스 기반 정책](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html)을 참조하세요.

인증 정책에는 다음 요소가 포함됩니다.
+ **보안 주체** - 문에서의 작업 및 리소스에 액세스할 수 있는 사람 또는 애플리케이션입니다. 인증 정책에서 보안 주체는 이 권한의 수신자인 IAM 엔터티입니다. 보안 주체는 IAM 엔티티로 인증되어 서비스 네트워크의 서비스 경우와 같이 특정 리소스 또는 리소스 그룹에 요청할 수 있습니다.

  리소스 기반 정책에서 보안 주체를 지정해야 합니다. 보안 주체에는 계정, 사용자, 역할, 페더레이션 사용자 또는 AWS 서비스가 포함될 수 있습니다. 자세한 내용은 *IAM 사용 설명서*의 [AWS JSON 정책 요소: 보안 주체](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html)를 참조하세요.
+ **결과** – 지정된 보안 주체가 특정 작업을 요청할 때의 결과입니다. 이는 `Allow` 또는 `Deny`일 수 있습니다. 기본적으로 IAM을 사용하여 서비스 또는 서비스 네트워크에 대한 액세스 제어를 활성화하면 보안 주체는 서비스 또는 서비스 네트워크에 요청할 권한이 없습니다.
+ **작업** - 권한을 부여하거나 거부하는 특정 API 작업입니다. VPC Lattice는 `vpc-lattice-svcs` 접두사를 사용하는 작업을 지원합니다. 자세한 내용은 *서비스 승인* 참조의 [Amazon VPC Lattice Services에서 정의한 작업을](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonvpclatticeservices.html#amazonvpclatticeservices-actions-as-permissions) 참조하세요.
+ **리소스** – 작업의 영향을 받는 리소스입니다.
+ **조건**: 조건은 선택 사항으로서 이를 사용하여 정책이 적용되는 시기를 제어할 수 있습니다. 자세한 내용은 *서비스 권한 부여 참조*의 [Amazon VPC Lattice 서비스의 조건 키](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonvpclatticeservices.html#amazonvpclatticeservices-policy-keys)를 참조하세요.

인증 정책을 생성하고 관리할 때 [IAM 정책 생성기](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create.html#access_policies_create-generator)를 사용하려고 할 수 있습니다.

**요구 사항**  
JSON의 정책에는 줄 바꿈이나 빈 줄이 포함되어서는 안 됩니다.

## 인증 정책의 리소스 형식
<a name="auth-policies-resource-format"></a>

다음 예와 같이 `<serviceARN>/<path>` 패턴이 있는 매칭 스키마를 사용하고 `Resource` 요소를 코딩하는 인증 정책을 생성하여 특정 리소스에 대한 액세스를 제한할 수 있습니다.


| 프로토콜 | 예제 | 
| --- | --- | 
| HTTP |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/vpc-lattice/latest/ug/auth-policies.html)  | 
| gRPC |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/vpc-lattice/latest/ug/auth-policies.html)  | 

`<serviceARN>`에는 다음의 Amazon 리소스 이름(ARN) 리소스 형식을 사용합니다.

```
arn:aws:vpc-lattice:region:account-id:service/service-id
```

예제:

```
"Resource": "arn:aws:vpc-lattice:us-west-2:123456789012:service/svc-0123456789abcdef0"
```

## 인증 정책에 사용할 수 있는 조건 키
<a name="auth-policies-condition-keys"></a>

인증 정책의 **조건** 요소에 있는 조건 키를 통해 액세스를 추가로 제어할 수 있습니다. 이러한 조건 키는 프로토콜과 요청이 [Signature Version 4(SigV4)](sigv4-authenticated-requests.md)로 서명되었는지 아니면 익명으로 서명되었는지에 따라 평가용으로 제공됩니다. 조건 키는 대소문자를 구분합니다.

AWS 는 `aws:PrincipalOrgID` 및와 같이 액세스를 제어하는 데 사용할 수 있는 전역 조건 키를 제공합니다`aws:SourceIp`. AWS 전역 조건 키 목록을 보려면 *IAM 사용 설명서*의 [AWS 전역 조건 컨텍스트 키를](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html) 참조하세요.

다음 스토리에서는 VPC Lattice 조건 키를 나열합니다. 자세한 내용은 *서비스 권한 부여 참조*의 [Amazon VPC Lattice 서비스의 조건 키](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonvpclatticeservices.html#amazonvpclatticeservices-policy-keys)를 참조하세요.


| 조건 키 | 설명 | 예제 | 익명의(인증되지 않은) 호출자가 사용할 수 있나요? | gRPC 사용 가능 | 
| --- | --- | --- | --- | --- | 
| vpc-lattice-svcs:Port | 요청이 있는 서비스 포트를 기준으로 액세스를 필터링합니다. | 80 | 예 | 예 | 
| vpc-lattice-svcs:RequestMethod | 요청의 방법을 기준으로 액세스를 필터링합니다. | GET | 예 | 항상 게시 | 
| vpc-lattice-svcs:RequestPath | 요청 URL의 경로 부분을 기준으로 액세스를 필터링합니다. | /path | 예 | 예 | 
| vpc-lattice-svcs:RequestHeader/header-name: value | 요청 헤더의 헤더 이름-값 쌍을 기준으로 액세스를 필터링합니다. | content-type: application/json | 예 | 예 | 
| vpc-lattice-svcs:RequestQueryString/key-name: value | 요청 URL에 있는 쿼리 문자열 키-값 페어를 기준으로 액세스를 필터링합니다. | quux: [corge, grault] | 예 | 아니요 | 
| vpc-lattice-svcs:ServiceNetworkArn | 요청을 수신하는 서비스의 서비스 네트워크에 대한 ARN을 기준으로 액세스를 필터링합니다. | arn:aws:vpc-lattice:us-west-2:123456789012:servicenetwork/sn-0123456789abcdef0 | 예 | 예 | 
| vpc-lattice-svcs:ServiceArn | 요청을 수신하는 서비스의 ARN을 기준으로 액세스를 필터링합니다. | arn:aws:vpc-lattice:us-west-2:123456789012:service/svc-0123456789abcdef0 | 예 | 예 | 
| vpc-lattice-svcs:SourceVpc | 요청이 있는 VPC를 기준으로 액세스를 필터링합니다. | vpc-1a2b3c4d | 예 | 예 | 
| vpc-lattice-svcs:SourceVpcOwnerAccount | 요청이 있는 VPC의 소유 계정을 기준으로 액세스를 필터링합니다. | 123456789012 | 예 | 예 | 

## 리소스 태그
<a name="resource-tags"></a>

*태그*는 사용자가 할당하거나가 AWS 리소스에 AWS 할당하는 메타데이터 레이블입니다. 각 태그는 두 부분으로 구성됩니다.
+ *태그 키*(예: `CostCenter`, `Environment` 또는 `Project`) 태그 키는 대/소문자를 구별합니다.
+ *태그 값*(예: `111122223333` 또는 `Production`)으로 알려진 선택적 필드 태그 값을 생략하는 것은 빈 문자열을 사용하는 것과 같습니다. 태그 키처럼 태그 값은 대/소문자를 구분합니다.

태그 지정에 대한 자세한 내용은 [태그를 사용하여 AWS 리소스에 대한 액세스 제어를](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html) 참조하세요.

`aws:ResourceTag/key` AWS 글로벌 조건 컨텍스트 키를 사용하여 인증 정책에서 태그를 사용할 수 있습니다.

다음 예제 정책은 태그가 인 서비스에 대한 액세스 권한을 부여합니다`Environment=Gamma`. 이 정책을 사용하면 하드 코딩 서비스 ARNs 또는 IDs.

```
{
  "Version": "2012-10-17", 		 	 	 		 	 	 
  "Statement": [
    {
      "Sid": "AllowGammaAccess",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "vpc-lattice-svcs:Invoke",
      "Resource": "arn:aws:vpc-lattice:us-west-2:123456789012:service/svc-0124446789abcdef0/*",
      "Condition": {
        "StringEquals": {
          "aws:ResourceTag/Environment": "Gamma",
        }
      }
    }
  ]
}
```

## 보안 주체 태그
<a name="principal-tags"></a>

호출자의 자격 증명에 연결된 태그를 기반으로 서비스 및 리소스에 대한 액세스를 제어할 수 있습니다. VPC Lattice는 `aws:PrincipalTag/context` 변수를 사용하여 사용자, 역할 또는 세션 태그의 모든 보안 주체 태그를 기반으로 액세스 제어를 지원합니다. 자세한 내용은 [IAM 보안 주체에 대한 액세스 제어](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_iam-tags.html#access_iam-tags_control-principals)를 참조하세요.

다음 예제 정책은 태그가 인 자격 증명에만 액세스 권한을 부여합니다`Team=Payments`. 이 정책을 사용하면 계정 IDs 또는 역할 ARNs.

```
{
  "Version": "2012-10-17", 		 	 	 		 	 	 
  "Statement": [
    {
      "Sid": "AllowPaymentsTeam",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "vpc-lattice-svcs:Invoke",
      "Resource": "arn:aws:vpc-lattice:us-west-2:123456789012:service/svc-0123456789abcdef0/*",
      "Condition": {
        "StringEquals": {
          "aws:PrincipalTag/Team": "Payments",
        }
      }
    }
  ]
}
```

## 익명의(인증되지 않은) 보안 주체
<a name="anonymous-unauthenticated-principals"></a>

익명 보안 주체는 [서명 버전 4(SigV4)](sigv4-authenticated-requests.md)로 AWS 요청에 서명하지 않고 서비스 네트워크에 연결된 VPC 내에 있는 호출자입니다. 인증 정책에서 허용하는 경우 익명의 보안 주체는 서비스 네트워크의 서비스에 인증되지 않은 요청을 할 수 있습니다.

## 인증 정책 예시
<a name="example-auth-policies"></a>

다음은 인증된 보안 주체가 요청을 해야 하는 인증 정책의 예시입니다.

모든 예시는 `us-west-2` 리전을 사용하며 가상의 계정 ID를 포함합니다.

**예제 1: 특정 AWS 조직의 서비스에 대한 액세스 제한**  
다음 인증 정책 예시는 정책이 적용되는 서비스 네트워크의 모든 서비스에 액세스할 수 있는 권한을 인증된 모든 요청에 부여합니다. 그러나 요청은 조건에 지정된 AWS 조직에 속한 보안 주체에서 시작되어야 합니다.

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

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": "*",
         "Action": "vpc-lattice-svcs:Invoke",
         "Resource": "*",
         "Condition": {
            "StringEquals": {
               "aws:PrincipalOrgID": [ 
                  "o-123456example"
               ]
            }
         }
      }
   ]
}
```

------

**예 2: 특정 IAM 역할에 의한 서비스 액세스 제한**  
다음 인증 정책 예시는 `Resource` 요소에 지정된 서비스에 대해 HTTP GET 요청을 보내기 위해 IAM 역할 `rates-client`를 사용하는 모든 인증된 요청에 권한을 부여합니다. `Resource` 요소의 리소스는 정책이 연결된 서비스와 동일합니다.

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

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect": "Allow",
         "Principal": {
            "AWS": [
               "arn:aws:iam::123456789012:role/rates-client"
            ]
         },
         "Action": "vpc-lattice-svcs:Invoke",
         "Resource": [
            "arn:aws:vpc-lattice:us-west-2:123456789012:service/svc-0123456789abcdef0/*"
         ],
         "Condition": {
            "StringEquals": {
               "vpc-lattice-svcs:RequestMethod": "GET"
            }
         }
      }
   ]
}
```

------

**예 3: 특정 VPC의 인증된 보안 주체에 의한 서비스 액세스 제한**  
다음 인증 정책 예시는 VPC ID가 `vpc-1a2b3c4d`인 VPC의 보안 주체가 인증된 요청을 하는 경우만 허용합니다.

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

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": "*",
         "Action": "vpc-lattice-svcs:Invoke",
         "Resource": "*",
         "Condition": {
            "StringNotEquals": {
               "aws:PrincipalType": "Anonymous"
            },
            "StringEquals": {
               "vpc-lattice-svcs:SourceVpc": "vpc-1a2b3c4d"
            }
         }
      }
   ]
}
```

------

## 권한 부여의 작동 방식
<a name="auth-policies-evaluation-logic"></a>

VPC Lattice 서비스가 요청을 수신하면 AWS 적용 코드는 모든 관련 권한 정책을 함께 평가하여 요청을 승인할지 거부할지를 결정합니다. 권한 부여 중에 요청 컨텍스트에 적용할 수 있는 모든 IAM 자격 증명 기반 정책 및 인증 정책을 평가합니다. 기본적으로 인증 유형이 `AWS_IAM`인 경우 모든 요청이 묵시적으로 거부됩니다. 모든 관련 정책의 명시적 허용은 기본 설정을 무시합니다.

승인에는 다음이 포함됩니다.
+ 모든 관련 IAM 자격 증명 기반 정책 및 인증 정책 수집
+ 정책 세트 결과 평가:
  + 요청자(예: IAM 사용자 또는 역할)에게 요청자가 속한 계정에서 작업을 수행할 수 있는 권한이 있는지 확인합니다. 명시적 허용 문이 없는 경우 요청을 승인하지 AWS 않습니다.
  + 서비스 네트워크의 인증 정책에서 해당 요청을 허용하는지 확인합니다. 인증 정책이 활성화되었지만 명시적 허용 문이 없는 경우는 요청을 승인하지 AWS 않습니다. 명시적 허용 문이 있거나 인증 유형이 `NONE`인 경우 코드는 계속 실행됩니다.
  + 서비스에 대한 인증 정책에서 해당 요청을 허용하는지 확인합니다. 인증 정책이 활성화되었지만 명시적 허용 문이 없는 경우는 요청을 승인하지 AWS 않습니다. 명시적 허용 문이 있거나 인증 유형이 `NONE`인 경우 적용 코드가 최종 **Allow** 결정을 반환합니다.
  + 어떠한 정책의 명시적 거부도 허용을 무시합니다.

다이어그램은 권한 부여 워크플로를 보여줍니다. 요청을 하면 관련 정책은 해당 서비스에 대한 요청 액세스를 허용하거나 거부합니다.

![\[권한 부여 워크플로\]](http://docs.aws.amazon.com/ko_kr/vpc-lattice/latest/ug/images/authpolicy.png)


# 보안 그룹을 사용하여 VPC Lattice의 트래픽 제어
<a name="security-groups"></a>

AWS 보안 그룹은 가상 방화벽 역할을 하여 연결된 엔터티와의 네트워크 트래픽을 제어합니다. VPC Lattice를 사용하면 보안 그룹을 생성하고 VPC를 서비스 네트워크에 연결하는 VPC 연결에 할당하여 서비스 네트워크에 추가 네트워크 수준 보안 보호를 적용할 수 있습니다. VPC 엔드포인트를 사용하여 VPC를 서비스 네트워크에 연결하는 경우 VPC 엔드포인트에도 보안 그룹을 할당할 수 있습니다. 마찬가지로 생성한 리소스 게이트웨이에 보안 그룹을 할당하여 VPC의 리소스에 액세스할 수 있습니다.

**Topics**
+ [관리형 접두사 목록](#managed-prefix-list)
+ [보안 그룹 규칙](#security-groups-rules)
+ [VPC 연결을 위한 보안 그룹 관리](#service-network-security-group)

## 관리형 접두사 목록
<a name="managed-prefix-list"></a>

VPC Lattice는 서비스 네트워크 연결을 사용하여 VPC를 서비스 네트워크에 연결할 때 VPC Lattice 네트워크를 통해 트래픽을 라우팅하는 데 사용되는 IP 주소를 포함하는 관리형 접두사 목록을 제공합니다. 이러한 IPs는 프라이빗 링크 로컬 IPs 또는 라우팅할 수 없는 퍼블릭 IPs.

 보안 그룹 규칙에서 VPC Lattice 관리형 접두사 목록을 참조할 수 있습니다. 이렇게 하면 트래픽이 클라이언트에서 VPC Lattice 서비스 네트워크를 통해 VPC Lattice 서비스 대상으로 흐를 수 있습니다.

예를 들어 미국 서부(오레곤) 리전(`us-west-2`)에 대상으로 등록된 EC2 인스턴스가 있다고 가정합시다. VPC Lattice 관리형 접두사 목록에서 인바운드 HTTPS 액세스를 허용하는 규칙을 인스턴스 보안 그룹에 추가하면 이 리전의 VPC Lattice 트래픽이 인스턴스에 도달할 수 있습니다. 보안 그룹에서 다른 모든 인바운드 규칙을 제거하면 VPC Lattice 트래픽 이외의 모든 트래픽이 인스턴스에 도달하는 것을 방지할 수 있습니다.

VPC Lattice의 관리형 접두사 목록 이름은 다음과 같습니다.
+ com.amazonaws.*region*.vpc-lattice
+ com.amazonaws.*region*.ipv6.vpc-lattice

자세한 내용은 *Amazon VPC 사용 설명서*의 [AWS관리형 접두사 목록](https://docs.aws.amazon.com/vpc/latest/userguide/working-with-aws-managed-prefix-lists.html#available-aws-managed-prefix-lists)을 참조하세요.

**Windows 및 macOS 클라이언트**  
VPC Lattice 접두사 목록의 주소는 링크-로컬 주소와 라우팅할 수 없는 퍼블릭 주소입니다. 이러한 클라이언트에서 VPC Lattice에 연결하는 경우 관리형 접두사 목록의 IP 주소를 클라이언트의 기본 IP 주소로 전달하도록 구성을 업데이트해야 합니다. 다음은 Windows 클라이언트의 구성을 업데이트하는 예제 명령입니다. 여기서 169.254.171.0는 관리형 접두사 목록의 주소 중 하나입니다.

```
C:\> route add 169.254.171.0 mask 255.255.255.0 primary-ip-address
```

다음은 macOS 클라이언트의 구성을 업데이트하는 예제 명령입니다. 여기서 169.254.171.0는 관리형 접두사 목록의 주소 중 하나입니다.

```
sudo route -n add -net 169.254.171.0 primary-ip-address 255.255.255.0
```

정적 경로를 생성하지 않으려면 VPC의 서비스 네트워크 엔드포인트를 사용하여 연결을 설정하는 것이 좋습니다. 자세한 내용은 [서비스 네트워크 VPC 엔드포인트 연결 관리](service-network-associations.md#service-network-vpc-endpoint-associations) 단원을 참조하십시오.

## 보안 그룹 규칙
<a name="security-groups-rules"></a>

보안 그룹이 있든 없든 VPC Lattice를 사용해도 기존 VPC 보안 그룹 구성에 영향을 주지 않습니다. 그러나 언제든지 자체 보안 그룹을 추가할 수 있습니다.

**주요 고려 사항**
+ 클라이언트에 대한 보안 그룹 규칙은 VPC Lattice로의 아웃바운드 트래픽을 제어합니다.
+ 대상에 대한 보안 그룹 규칙은 상태 확인 트래픽을 포함하여 VPC Lattice에서 대상으로 가는 인바운드 트래픽을 제어합니다.
+ 서비스 네트워크와 VPC 간의 연결을 위한 보안 그룹 규칙은 VPC Lattice 서비스 네트워크에 액세스할 수 있는 클라이언트를 제어합니다.
+ 리소스 게이트웨이에 대한 보안 그룹 규칙은 리소스 게이트웨이에서 리소스로의 아웃바운드 트래픽을 제어합니다.

**리소스 게이트웨이에서 데이터베이스 리소스로 흐르는 트래픽에 대한 권장 아웃바운드 규칙**  
트래픽이 리소스 게이트웨이에서 리소스로 흐르려면 열린 포트에 대한 아웃바운드 규칙과 리소스에 대해 허용되는 리스너 프로토콜을 생성해야 합니다.


| Destination | 프로토콜 | 포트 범위 | 설명 | 
| --- | --- | --- | --- | 
| 리소스의 CIDR 범위 | TCP | 3306 | 리소스 게이트웨이에서 데이터베이스로의 트래픽 허용 | 

**서비스 네트워크 및 VPC 연결을 위한 권장 인바운드 규칙**  
트래픽VPCs에서 서비스 네트워크와 연결된 서비스로 흐르려면 서비스에 대한 리스너 포트 및 리스너 프로토콜에 대한 인바운드 규칙을 생성해야 합니다.


| 소스 | 프로토콜 | 포트 범위 | Comment | 
| --- | --- | --- | --- | 
| VPC CIDR | listener | listener | 클라이언트에서 VPC Lattice로의 트래픽 허용 | 

**클라이언트 인스턴스에서 VPC Lattice로의 트래픽 흐름에 대한 권장 아웃바운드 규칙**  
기본적으로 보안 그룹은 모든 아웃바운드 트래픽을 허용합니다. 그러나 사용자 지정 아웃바운드 규칙이 있는 경우 클라이언트 인스턴스가 VPC Lattice 서비스 네트워크와 연결된 모든 서비스에 연결할 수 있도록 리스너 포트 및 프로토콜에 대해 VPC Lattice 접두사로의 아웃바운드 트래픽을 허용해야 합니다. VPC Lattice에 대한 접두사 목록의 ID를 참조하여이 트래픽을 허용할 수 있습니다.


| Destination | 프로토콜 | 포트 범위 | 설명 | 
| --- | --- | --- | --- | 
| VPC Lattice 접두사 목록의 ID | listener | listener | 클라이언트에서 VPC Lattice로의 트래픽 허용 | 

**VPC Lattice에서 대상 인스턴스로의 트래픽 흐름에 대한 권장 인바운드 규칙**  
트래픽이 VPC Lattice에서 흐르기 때문에 클라이언트 보안 그룹을 대상 보안 그룹의 소스로 사용할 수 없습니다. VPC Lattice에 대한 접두사 목록의 ID를 참조할 수 있습니다.


| 소스 | 프로토콜 | 포트 범위 | 설명 | 
| --- | --- | --- | --- | 
| VPC Lattice 접두사 목록의 ID | target | target | VPC Lattice에서 대상으로의 트래픽 허용 | 
| VPC Lattice 접두사 목록의 ID | health check | health check | VPC Lattice에서 대상으로 가는 상태 확인 트래픽 허용 | 

## VPC 연결을 위한 보안 그룹 관리
<a name="service-network-security-group"></a>

 AWS CLI 를 사용하여 VPC에서 서비스 네트워크 연결에 대한 보안 그룹을 보거나 추가하거나 업데이트할 수 있습니다. 를 사용할 때 명령은 프로파일에 대해 AWS 리전 구성된에서 실행 AWS CLI됩니다. 다른 리전에서 명령을 실행하려는 경우 프로필의 기본 리전을 변경하거나 명령에 `--region` 파라미터를 사용합니다.

시작하기 전에 서비스 네트워크에 추가하려는 VPC와 동일한 VPC에 보안 그룹을 생성했는지 확인합니다. 자세한 내용은 *Amazon VPC 사용 설명서*의 [보안 그룹을 사용하여 리소스에 대한 트래픽 제어를 참조하세요](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html).

**콘솔을 사용하여 VPC 연결을 생성할 때 보안 그룹을 추가하는 방법**

1. [https://console.aws.amazon.com/vpc/](https://console.aws.amazon.com/vpc/)에서 Amazon VPC 콘솔을 엽니다.

1. 탐색 창의 **VPC Lattice**에서 **서비스 네트워크**를 선택합니다.

1. 서비스 네트워크의 이름을 선택하여 세부 정보 페이지를 엽니다.

1. **VPC 연결** 탭에서 **VPC 연결 생성**을 선택한 다음 **VPC 연결 추가**를 선택합니다.

1. VPC와 최대 5개의 보안 그룹을 선택합니다.

1. **변경 사항 저장**을 선택합니다.

**콘솔을 사용하여 기존 VPC 연결에 대한 보안 그룹을 추가 또는 업데이트하는 방법**

1. [https://console.aws.amazon.com/vpc/](https://console.aws.amazon.com/vpc/)에서 Amazon VPC 콘솔을 엽니다.

1. 탐색 창의 **VPC Lattice**에서 **서비스 네트워크**를 선택합니다.

1. 서비스 네트워크의 이름을 선택하여 세부 정보 페이지를 엽니다.

1. **VPC 연결** 탭에서 연결의 확인란을 선택한 다음 **작업**, **보안 그룹 편집**을 선택합니다.

1. 필요에 따라 보안 그룹을 추가하고 제거합니다.

1. **변경 사항 저장**을 선택합니다.

**를 사용하여 VPC 연결을 생성할 때 보안 그룹을 추가하려면 AWS CLI**  
[create-service-network-vpc-association](https://docs.aws.amazon.com/cli/latest/reference/vpc-lattice/create-service-network-vpc-association.html) 명령을 사용하여 VPC 연결을 위한 VPC의 ID와 추가할 보안 그룹의 ID를 지정합니다.

```
aws vpc-lattice create-service-network-vpc-association \
    --service-network-identifier sn-0123456789abcdef0 \
    --vpc-identifier vpc-1a2b3c4d \
    --security-group-ids sg-7c2270198example
```

이 작업이 성공하면 다음과 비슷한 출력이 반환됩니다.

```
{
  "arn": "arn",
  "createdBy": "464296918874",
  "id": "snva-0123456789abcdef0",
  "status": "CREATE_IN_PROGRESS",
  "securityGroupIds": ["sg-7c2270198example"]
}
```

**를 사용하여 기존 VPC 연결에 대한 보안 그룹을 추가하거나 업데이트하려면 AWS CLI**  
[update-service-network-vpc-association](https://docs.aws.amazon.com/cli/latest/reference/vpc-lattice/update-service-network-vpc-association.html) 명령을 사용하여 서비스 네트워크의 ID와 보안 그룹의 ID를 지정합니다. 이 보안 그룹은 이전에 연결된 보안 그룹을 재정의합니다. 목록을 업데이트할 때 보안 그룹을 하나 이상 정의합니다.

```
aws vpc-lattice update-service-network-vpc-association 
    --service-network-vpc-association-identifier sn-903004f88example \
    --security-group-ids sg-7c2270198example sg-903004f88example
```

**주의**  
모든 보안 그룹을 제거할 수 없습니다. 대신 먼저 VPC 연결을 삭제한 다음 보안 그룹 없이 VPC 연결을 다시 생성해야 합니다. VPC 연결을 삭제할 때는 주의해야 합니다. 삭제하면 트래픽이 해당 서비스 네트워크에 있는 서비스에 도달하지 못하게 됩니다.

# 네트워크 ACL을 사용하여 VPC Lattice에 대한 트래픽 제어
<a name="network-acls"></a>

네트워크 액세스 제어 목록(ACL)은 서브넷 수준에서 특정 인바운드 또는 아웃바운드 트래픽을 허용하거나 거부합니다. 기본 네트워크 ACL은 인바운드와 아웃바운드 트래픽을 모두 허용합니다. 서브넷에 대한 사용자 지정 네트워크 ACLs을 생성하여 추가 보안 계층을 제공할 수 있습니다. 자세한 내용을 알아보려면 Amazon VPC 사용 설명서**의 [네트워크 ACL](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html)을 참조하세요.

**Topics**
+ [클라이언트 서브넷ACLs](#network-acl-client-subnets)
+ [대상 서브넷ACLs](#network-acl-target-subnets)

## 클라이언트 서브넷ACLs
<a name="network-acl-client-subnets"></a>

클라이언트 서브넷ACLs은 클라이언트와 VPC Lattice 간의 트래픽을 허용해야 합니다. VPC Lattice의 [관리형 접두사 목록에서](security-groups.md#managed-prefix-list) 허용할 IP 주소 범위를 가져올 수 있습니다.

다음은 인바운드 규칙의 예입니다.


| 소스 | 프로토콜 | 포트 범위 | 설명 | 
| --- | --- | --- | --- | 
| vpc\$1lattice\$1cidr\$1block | TCP | 1025-65535 | VPC Lattice에서 클라이언트로의 트래픽 허용 | 

다음은 아웃바운드 예제입니다.


| Destination | 프로토콜 | 포트 범위 | 설명 | 
| --- | --- | --- | --- | 
| vpc\$1lattice\$1cidr\$1block | listener | listener | 클라이언트에서 VPC Lattice로의 트래픽 허용 | 

## 대상 서브넷ACLs
<a name="network-acl-target-subnets"></a>

대상 서브넷의 네트워크 ACLs은 대상 포트와 상태 확인 포트 모두에서 대상과 VPC Lattice 간의 트래픽을 허용해야 합니다. VPC Lattice의 [관리형 접두사 목록에서](security-groups.md#managed-prefix-list) 허용할 IP 주소 범위를 가져올 수 있습니다.

다음은 인바운드 규칙의 예입니다.


| 소스 | 프로토콜 | 포트 범위 | 설명 | 
| --- | --- | --- | --- | 
| vpc\$1lattice\$1cidr\$1block | target | target | VPC Lattice에서 대상으로의 트래픽 허용 | 
| vpc\$1lattice\$1cidr\$1block | health check | health check | VPC Lattice에서 대상으로 가는 상태 확인 트래픽 허용 | 

다음은 아웃바운드 예제입니다.


| Destination | 프로토콜 | 포트 범위 | 설명 | 
| --- | --- | --- | --- | 
| vpc\$1lattice\$1cidr\$1block | target | 1024-65535 | 대상에서 VPC Lattice로의 트래픽 허용 | 
| vpc\$1lattice\$1cidr\$1block | health check | 1024-65535 | 대상에서 VPC Lattice로의 상태 확인 트래픽 허용 | 

# Amazon VPC Lattice에 대한 SIGv4 인증 요청
<a name="sigv4-authenticated-requests"></a>

VPC Lattice는 클라이언트 인증에 서명 버전 4(SIGv4) 또는 서명 버전 4A(SIGv4A)를 사용합니다. 자세한 내용은 *IAM 사용 설명서*의 [API 요청용AWS Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html) 섹션을 참조하세요.

**고려 사항**
+ VPC Lattice는 SIGv4 또는 SIGv4A로 서명된 모든 요청을 인증하려고 시도합니다. 인증하지 않으면 요청이 실패합니다.
+ VPC Lattice는 페이로드 서명을 지원하지 않습니다. 값이 `"UNSIGNED-PAYLOAD"`로 설정된 `x-amz-content-sha256` 헤더를 보내야 합니다.

**Topics**
+ [Python](#sigv4-authenticated-requests-python)
+ [Java](#sigv4-authenticated-requests-java-custom-interceptor)
+ [Node.js](#sigv4-authenticated-requests-nodejs)
+ [Golang](#sigv4-authenticated-requests-golang)
+ [골랑 - GRPC](#sigv4-authenticated-requests-golang-grpc)

## Python
<a name="sigv4-authenticated-requests-python"></a>

이 예제에서는 네트워크에 등록된 서비스에 대한 보안 연결을 통해 서명된 요청을 보냅니다. [요청](https://requests.readthedocs.io/en/latest/)을 사용하려는 경우 [botocore](https://github.com/boto/botocore) 패키지는 인증 프로세스를 간소화하지만 엄격히 요구되는 것은 아닙니다. 자세한 내용은 Boto3 설명서의 [자격 증명을 참조하세요](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html).

`botocore` 및 `awscrt` 패키지를 설치하려면 다음 명령을 사용합니다. 자세한 내용은 [AWS CRT Python](https://pypi.org/project/awscrt/)을 참조하세요.

```
pip install botocore awscrt
```

Lambda에서 클라이언트 애플리케이션을 실행하는 경우 [Lambda 계층](https://docs.aws.amazon.com/lambda/latest/dg/python-layers.html)을 사용하여 필요한 모듈을 설치하거나 배포 패키지에 포함합니다.

다음 예제에서는 자리 표시자 값을 고유한 값으로 바꿉니다.

------
#### [ SIGv4 ]

```
from botocore import crt
import requests 
from botocore.awsrequest import AWSRequest
import botocore.session

if __name__ == '__main__':
    session = botocore.session.Session()
    signer = crt.auth.CrtSigV4Auth(session.get_credentials(), 'vpc-lattice-svcs', 'us-west-2')
    endpoint = 'https://data-svc-022f67d3a42.1234abc.vpc-lattice-svcs.us-west-2.on.aws'
    data = "some-data-here"
    headers = {'Content-Type': 'application/json', 'x-amz-content-sha256': 'UNSIGNED-PAYLOAD'}
    request = AWSRequest(method='POST', url=endpoint, data=data, headers=headers)
    request.context["payload_signing_enabled"] = False
    signer.add_auth(request)
    
    prepped = request.prepare()
    
    response = requests.post(prepped.url, headers=prepped.headers, data=data)
    print(response.text)
```

------
#### [ SIGv4A ]

```
from botocore import crt
import requests 
from botocore.awsrequest import AWSRequest
import botocore.session

if __name__ == '__main__':
    session = botocore.session.Session()
    signer = crt.auth.CrtSigV4AsymAuth(session.get_credentials(), 'vpc-lattice-svcs', '*')
    endpoint = 'https://data-svc-022f67d3a42.1234abc.vpc-lattice-svcs.us-west-2.on.aws'
    data = "some-data-here"
    headers = {'Content-Type': 'application/json', 'x-amz-content-sha256': 'UNSIGNED-PAYLOAD'}
    request = AWSRequest(method='POST', url=endpoint, data=data, headers=headers)
    request.context["payload_signing_enabled"] = False 
    signer.add_auth(request)
    
    prepped = request.prepare()
    
    response = requests.post(prepped.url, headers=prepped.headers, data=data)
    print(response.text)
```

------

## Java
<a name="sigv4-authenticated-requests-java-custom-interceptor"></a>

이 예시에서는 사용자 지정 인터셉터를 사용하여 요청 서명을 수행하는 방법을 보여줍니다. 올바른 보안 인증을 가져오는 [AWS SDK for Java 2.x](https://github.com/aws/aws-sdk-java-v2)의 기본 자격 증명 공급자 클래스를 사용합니다. 특정 보안 인증 공급자를 사용하려면 [AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials.html)에서 하나를 선택할 수 있습니다. 는 HTTPS를 통한 서명되지 않은 페이로드만 AWS SDK for Java 허용합니다. 하지만 HTTP를 통한 서명되지 않은 페이로드를 지원하도록 서명자를 확장할 수 있습니다.

------
#### [ SIGv4 ]

```
package com.example;

import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner;
import software.amazon.awssdk.http.auth.spi.signer.SignedRequest;

import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.http.HttpExecuteRequest;
import software.amazon.awssdk.http.HttpExecuteResponse;
import java.io.IOException;
import java.net.URI;

import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;

public class sigv4 {

    public static void main(String[] args) {
        AwsV4HttpSigner signer = AwsV4HttpSigner.create();

        AwsCredentialsIdentity credentials = DefaultCredentialsProvider.create().resolveCredentials();

        if (args.length < 2) {
            System.out.println("Usage: sample <url> <region>");
            System.exit(1);
        }
        // Create the HTTP request to be signed
        var url = args[0];
        SdkHttpRequest httpRequest = SdkHttpRequest.builder()
                .uri(URI.create(url))
                .method(SdkHttpMethod.GET)
                .build();

        SignedRequest signedRequest = signer.sign(r -> r.identity(credentials)
                .request(httpRequest)
                .putProperty(AwsV4HttpSigner.SERVICE_SIGNING_NAME, "vpc-lattice-svcs")
                .putProperty(AwsV4HttpSigner.PAYLOAD_SIGNING_ENABLED, false)
                .putProperty(AwsV4HttpSigner.REGION_NAME, args[1]));

        System.out.println("[*] Raw request headers:");
        signedRequest.request().headers().forEach((key, values) -> {
            values.forEach(value -> System.out.println("  " + key + ": " + value));
        });

        try (SdkHttpClient httpClient = ApacheHttpClient.create()) {
            HttpExecuteRequest httpExecuteRequest = HttpExecuteRequest.builder()
                    .request(signedRequest.request())
                    .contentStreamProvider(signedRequest.payload().orElse(null))
                    .build();

            System.out.println("[*] Sending request to: " + url);

            HttpExecuteResponse httpResponse = httpClient.prepareRequest(httpExecuteRequest).call();

            System.out.println("[*] Request sent");

            System.out.println("[*] Response status code: " + httpResponse.httpResponse().statusCode());
            // Read and print the response body
            httpResponse.responseBody().ifPresent(inputStream -> {
                try {
                    String responseBody = new String(inputStream.readAllBytes());
                    System.out.println("[*] Response body: " + responseBody);
                } catch (IOException e) {
                    System.err.println("[*] Failed to read response body");
                    e.printStackTrace();
                } finally {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        System.err.println("[*] Failed to close input stream");
                        e.printStackTrace();
                    }
                }
            });
        } catch (IOException e) {
            System.err.println("[*] HTTP Request Failed.");
            e.printStackTrace();
        }

    }
}
```

------
#### [ SIGv4A ]

이 예제에서는에 대한 추가 종속성이 필요합니다`software.amazon.awssdk:http-auth-aws-crt`.

```
package com.example;


import software.amazon.awssdk.http.auth.aws.signer.AwsV4aHttpSigner;
import software.amazon.awssdk.http.auth.aws.signer.RegionSet;
import software.amazon.awssdk.http.auth.spi.signer.SignedRequest;

import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.http.SdkHttpClient;
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.http.HttpExecuteRequest;
import software.amazon.awssdk.http.HttpExecuteResponse;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;

import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;

public class sigv4a {
    
    public static void main(String[] args) {
        AwsV4aHttpSigner signer = AwsV4aHttpSigner.create();

        AwsCredentialsIdentity credentials = DefaultCredentialsProvider.create().resolveCredentials();

        if (args.length < 2) {
            System.out.println("Usage: sample <url> <regionset>");
            System.exit(1);
        }
        // Create the HTTP request to be signed
        var url = args[0];
        SdkHttpRequest httpRequest = SdkHttpRequest.builder()
                .uri(URI.create(url))
                .method(SdkHttpMethod.GET)
                .build();

        SignedRequest signedRequest = signer.sign(r -> r.identity(credentials)
                .request(httpRequest)
                .putProperty(AwsV4aHttpSigner.SERVICE_SIGNING_NAME, "vpc-lattice-svcs")
                .putProperty(AwsV4aHttpSigner.PAYLOAD_SIGNING_ENABLED, false)
                .putProperty(AwsV4aHttpSigner.REGION_SET, RegionSet.create(String.join(" ",Arrays.copyOfRange(args, 1, args.length)))));

        System.out.println("[*] Raw request headers:");
        signedRequest.request().headers().forEach((key, values) -> {
            values.forEach(value -> System.out.println("  " + key + ": " + value));
        });

        try (SdkHttpClient httpClient = ApacheHttpClient.create()) {
            HttpExecuteRequest httpExecuteRequest = HttpExecuteRequest.builder()
                    .request(signedRequest.request())
                    .contentStreamProvider(signedRequest.payload().orElse(null))
                    .build();

            System.out.println("[*] Sending request to: " + url);

            HttpExecuteResponse httpResponse = httpClient.prepareRequest(httpExecuteRequest).call();

            System.out.println("[*] Request sent");

            System.out.println("[*] Response status code: " + httpResponse.httpResponse().statusCode());
            // Read and print the response body
            httpResponse.responseBody().ifPresent(inputStream -> {
                try {
                    String responseBody = new String(inputStream.readAllBytes());
                    System.out.println("[*] Response body: " + responseBody);
                } catch (IOException e) {
                    System.err.println("[*] Failed to read response body");
                    e.printStackTrace();
                } finally {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        System.err.println("[*] Failed to close input stream");
                        e.printStackTrace();
                    }
                }
            });
        } catch (IOException e) {
            System.err.println("[*] HTTP Request Failed.");
            e.printStackTrace();
        }
    }
}
```

------

## Node.js
<a name="sigv4-authenticated-requests-nodejs"></a>

이 예시에서는 [aws-crt NodeJS 바인딩](https://github.com/awslabs/aws-crt-nodejs)을 사용하여 HTTPS를 사용하여 서명된 요청을 보냅니다.

`aws-crt` 패키지를 설치하려면 다음 명령을 실행합니다.

```
npm -i aws-crt
```

`AWS_REGION` 환경 변수가 있는 경우 예시에서는 `AWS_REGION`에서 지정한 리전을 사용합니다. 기본 리전은 `us-east-1`입니다.

------
#### [ SIGv4 ]

```
const https = require('https')
const crt = require('aws-crt')
const { HttpRequest } = require('aws-crt/dist/native/http')

function sigV4Sign(method, endpoint, service, algorithm) {
    const host = new URL(endpoint).host
    const request = new HttpRequest(method, endpoint)
    request.headers.add('host', host)
    // crt.io.enable_logging(crt.io.LogLevel.INFO)
    const config = {
        service: service,
        region: process.env.AWS_REGION ? process.env.AWS_REGION : 'us-east-1',
        algorithm: algorithm,
        signature_type: crt.auth.AwsSignatureType.HttpRequestViaHeaders,
        signed_body_header: crt.auth.AwsSignedBodyHeaderType.XAmzContentSha256,
        signed_body_value: crt.auth.AwsSignedBodyValue.UnsignedPayload,
        provider: crt.auth.AwsCredentialsProvider.newDefault()
    }

    return crt.auth.aws_sign_request(request, config)
}

if (process.argv.length === 2) {
  console.error(process.argv[1] + ' <url>')
  process.exit(1)
}

const algorithm = crt.auth.AwsSigningAlgorithm.SigV4;

sigV4Sign('GET', process.argv[2], 'vpc-lattice-svcs', algorithm).then(
  httpResponse => {
    var headers = {}

    for (const sigv4header of httpResponse.headers) {
      headers[sigv4header[0]] = sigv4header[1]
    }

    const options = {
      hostname: new URL(process.argv[2]).host,
      path: new URL(process.argv[2]).pathname,
      method: 'GET',
      headers: headers
    }

    req = https.request(options, res => {
      console.log('statusCode:', res.statusCode)
      console.log('headers:', res.headers)
      res.on('data', d => {
        process.stdout.write(d)
      })
    })
    req.on('error', err => {
      console.log('Error: ' + err)
    })
    req.end()
  }
)
```

------
#### [ SIGv4A ]

```
const https = require('https')
const crt = require('aws-crt')
const { HttpRequest } = require('aws-crt/dist/native/http')

function sigV4Sign(method, endpoint, service, algorithm) {
    const host = new URL(endpoint).host
    const request = new HttpRequest(method, endpoint)
    request.headers.add('host', host)
    // crt.io.enable_logging(crt.io.LogLevel.INFO)
    const config = {
        service: service,
        region: process.env.AWS_REGION ? process.env.AWS_REGION : 'us-east-1',
        algorithm: algorithm,
        signature_type: crt.auth.AwsSignatureType.HttpRequestViaHeaders,
        signed_body_header: crt.auth.AwsSignedBodyHeaderType.XAmzContentSha256,
        signed_body_value: crt.auth.AwsSignedBodyValue.UnsignedPayload,
        provider: crt.auth.AwsCredentialsProvider.newDefault()
    }

    return crt.auth.aws_sign_request(request, config)
}

if (process.argv.length === 2) {
  console.error(process.argv[1] + ' <url>')
  process.exit(1)
}

const algorithm = crt.auth.AwsSigningAlgorithm.SigV4Asymmetric;

sigV4Sign('GET', process.argv[2], 'vpc-lattice-svcs', algorithm).then(
  httpResponse => {
    var headers = {}

    for (const sigv4header of httpResponse.headers) {
      headers[sigv4header[0]] = sigv4header[1]
    }

    const options = {
      hostname: new URL(process.argv[2]).host,
      path: new URL(process.argv[2]).pathname,
      method: 'GET',
      headers: headers
    }

    req = https.request(options, res => {
      console.log('statusCode:', res.statusCode)
      console.log('headers:', res.headers)
      res.on('data', d => {
        process.stdout.write(d)
      })
    })
    req.on('error', err => {
      console.log('Error: ' + err)
    })
    req.end()
  }
)
```

------

## Golang
<a name="sigv4-authenticated-requests-golang"></a>

이 예제에서는 [Go용 Smithy 코드 생성기와](https://github.com/aws/smithy-go) [AWS Go 프로그래밍 언어용 SDK](https://github.com/aws/aws-sdk-go)를 사용하여 요청 서명 요청을 처리합니다. 이 예제에서는 Go 버전 1.21 이상이 필요합니다.

------
#### [ SIGv4 ]

```
package main
 
import (
        "context"
        "flag"
        "fmt"
        "io"
        "log"
        "net/http"
        "net/http/httputil"
        "os"
        "strings"
 
        "github.com/aws/aws-sdk-go-v2/aws"
        "github.com/aws/aws-sdk-go-v2/config"
        "github.com/aws/smithy-go/aws-http-auth/credentials"
        "github.com/aws/smithy-go/aws-http-auth/sigv4"
        v4 "github.com/aws/smithy-go/aws-http-auth/v4"
)
 
type nopCloser struct {
        io.ReadSeeker
}
 
func (nopCloser) Close() error {
        return nil
}
 
type stringFlag struct {
        set   bool
        value string
}
 
 
        flag.PrintDefaults()
        os.Exit(1)
}
 
func main() {
        flag.Parse()
        if !url.set || !region.set {
                Usage()
        }
 
        cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithClientLogMode(aws.LogSigning))
        if err != nil {
                log.Fatalf("failed to load SDK configuration, %v", err)
        }
 
        if len(os.Args) < 2 {
                log.Fatalf("Usage: go run main.go  <url>")
        }
 
        // Retrieve credentials from an SDK source, such as the instance profile
        sdkCreds, err := cfg.Credentials.Retrieve(context.TODO())
        if err != nil {
                log.Fatalf("Unable to retrieve credentials from SDK, %v", err)
        }
 
        creds := credentials.Credentials{
                AccessKeyID:     sdkCreds.AccessKeyID,
                SecretAccessKey: sdkCreds.SecretAccessKey,
                SessionToken:    sdkCreds.SessionToken,
        }
 
        // Add a payload body, which will not be part of the signature calculation
        body := nopCloser{strings.NewReader(`Example payload body`)}
 
        req, _ := http.NewRequest(http.MethodPost, url.value, body)
 
        // Create a sigv4a signer with specific options
        signer := sigv4.New(func(o *v4.SignerOptions) {
                o.DisableDoublePathEscape = true
                // This will add the UNSIGNED-PAYLOAD sha256 header
                o.AddPayloadHashHeader = true
                o.DisableImplicitPayloadHashing = true
        })
 
        // Perform the signing on req, using the credentials we retrieved from the SDK
        err = signer.SignRequest(&sigv4.SignRequestInput{
                Request:     req,
                Credentials: creds,
                Service:     "vpc-lattice-svcs",
                Region: region.String(),
        })
 
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        res, err := httputil.DumpRequest(req, true)
 
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        log.Printf("[*] Raw request\n%s\n", string(res))
 
        log.Printf("[*] Sending request to %s\n", url.value)
 
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        log.Printf("[*] Request sent\n")
 
        log.Printf("[*] Response status code: %d\n", resp.StatusCode)
 
        respBody, err := io.ReadAll(resp.Body)
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        log.Printf("[*] Response body: \n%s\n", respBody)
}
```

------
#### [ SIGv4A ]

```
package main
 
import (
        "context"
        "flag"
        "fmt"
        "io"
        "log"
        "net/http"
        "net/http/httputil"
        "os"
        "strings"
 
        "github.com/aws/aws-sdk-go-v2/aws"
        "github.com/aws/aws-sdk-go-v2/config"
        "github.com/aws/smithy-go/aws-http-auth/credentials"
        "github.com/aws/smithy-go/aws-http-auth/sigv4a"
        v4 "github.com/aws/smithy-go/aws-http-auth/v4"
)
 
type nopCloser struct {
        io.ReadSeeker
}
 
func (nopCloser) Close() error {
        return nil
}
 
type stringFlag struct {
 
func main() {
        flag.Parse()
        if !url.set || !regionSet.set {
                Usage()
        }
 
        cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithClientLogMode(aws.LogSigning))
        if err != nil {
                log.Fatalf("failed to load SDK configuration, %v", err)
        }
 
        if len(os.Args) < 2 {
                log.Fatalf("Usage: go run main.go <url>")
        }
 
        // Retrieve credentials from an SDK source, such as the instance profile
        sdkCreds, err := cfg.Credentials.Retrieve(context.TODO())
        if err != nil {
                log.Fatalf("Unable to retrieve credentials from SDK, %v", err)
        }
 
        creds := credentials.Credentials{
                AccessKeyID:     sdkCreds.AccessKeyID,
                SecretAccessKey: sdkCreds.SecretAccessKey,
                SessionToken:    sdkCreds.SessionToken,
        }
 
        // Add a payload body, which will not be part of the signature calculation
        body := nopCloser{strings.NewReader(`Example payload body`)}
 
        req, _ := http.NewRequest(http.MethodPost, url.value, body)
 
        // Create a sigv4a signer with specific options
        signer := sigv4a.New(func(o *v4.SignerOptions) {
                o.DisableDoublePathEscape = true
                // This will add the UNSIGNED-PAYLOAD sha256 header
                o.AddPayloadHashHeader = true
                o.DisableImplicitPayloadHashing = true
        })
 
        // Create a slice out of the provided regionset
        rs := strings.Split(regionSet.value, ",")
 
        // Perform the signing on req, using the credentials we retrieved from the SDK
        err = signer.SignRequest(&sigv4a.SignRequestInput{
                Request:     req,
                Credentials: creds,
                Service:     "vpc-lattice-svcs",
                RegionSet: rs,
        })
 
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        res, err := httputil.DumpRequest(req, true)
 
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        log.Printf("[*] Raw request\n%s\n", string(res))
 
        log.Printf("[*] Sending request to %s\n", url.value)
 
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        log.Printf("[*] Request sent\n")
 
        log.Printf("[*] Response status code: %d\n", resp.StatusCode)
 
        respBody, err := io.ReadAll(resp.Body)
        if err != nil {
                log.Fatalf("%s", err)
        }
 
        log.Printf("[*] Response body: \n%s\n", respBody)
}
```

------

## 골랑 - GRPC
<a name="sigv4-authenticated-requests-golang-grpc"></a>

이 예제에서는 [AWS Go 프로그래밍 언어용 SDK](https://github.com/aws/aws-sdk-go-v2/)를 사용하여 GRPC 요청에 대한 요청 서명을 처리합니다. 이는 GRPC 샘플 코드 리포지토리의 [에코 서버에서](https://github.com/grpc/grpc-go/tree/master/examples/features/proto/echo) 사용할 수 있습니다.

```
package main

import (
    "context"
    "crypto/tls"
    "crypto/x509"

    "flag"
    "fmt"
    "log"
    "net/http"
    "net/url"
    "strings"
    "time"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"

    "github.com/aws/aws-sdk-go-v2/aws"
    v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
    "github.com/aws/aws-sdk-go-v2/config"

    ecpb "google.golang.org/grpc/examples/features/proto/echo"
)

const (
    headerContentSha    = "x-amz-content-sha256"
    headerSecurityToken = "x-amz-security-token"
    headerDate          = "x-amz-date"
    headerAuthorization = "authorization"
    unsignedPayload     = "UNSIGNED-PAYLOAD"
)

type SigV4GrpcSigner struct {
    service      string
    region       string
    credProvider aws.CredentialsProvider
    signer       *v4.Signer
}

func NewSigV4GrpcSigner(service string, region string, credProvider aws.CredentialsProvider) *SigV4GrpcSigner {
    signer := v4.NewSigner()
    return &SigV4GrpcSigner{
        service:      service,
        region:       region,
        credProvider: credProvider,
        signer:       signer,
    }
}

func (s *SigV4GrpcSigner) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
    ri, _ := credentials.RequestInfoFromContext(ctx)
    creds, err := s.credProvider.Retrieve(ctx)
    if err != nil {
        return nil, fmt.Errorf("failed to load credentials: %w", err)
    }

    // The URI we get here is scheme://authority/service/ - for siging we want to include the RPC name
    // But RequestInfoFromContext only has the combined /service/rpc-name - so read the URI, and
    // replace the Path with what we get from RequestInfo.
    parsed, err := url.Parse(uri[0])
    if err != nil {
        return nil, err
    }
    parsed.Path = ri.Method

    // Build a request for the signer.
    bodyReader := strings.NewReader("")
    req, err := http.NewRequest("POST", uri[0], bodyReader)
    if err != nil {
        return nil, err
    }
    date := time.Now()
    req.Header.Set(headerContentSha, unsignedPayload)
    req.Header.Set(headerDate, date.String())
    if creds.SessionToken != "" {
        req.Header.Set(headerSecurityToken, creds.SessionToken)
    }
    // The signer wants this as //authority/path
    // So get this by triming off the scheme and the colon before the first slash.
    req.URL.Opaque = strings.TrimPrefix(parsed.String(), parsed.Scheme+":")

    err = s.signer.SignHTTP(context.Background(), creds, req, unsignedPayload, s.service, s.region, date)
    if err != nil {
        return nil, fmt.Errorf("failed to sign request: %w", err)
    }

    // Pull the relevant headers out of the signer, and return them to get
    // included in the request we make.
    reqHeaders := map[string]string{
        headerContentSha:    req.Header.Get(headerContentSha),
        headerDate:          req.Header.Get(headerDate),
        headerAuthorization: req.Header.Get(headerAuthorization),
    }
    if req.Header.Get(headerSecurityToken) != "" {
        reqHeaders[headerSecurityToken] = req.Header.Get(headerSecurityToken)
    }

    return reqHeaders, nil
}

func (c *SigV4GrpcSigner) RequireTransportSecurity() bool {
    return true
}

var addr = flag.String("addr", "some-lattice-service:443", "the address to connect to")
var region = flag.String("region", "us-west-2", "region")

func callUnaryEcho(client ecpb.EchoClient, message string) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    resp, err := client.UnaryEcho(ctx, &ecpb.EchoRequest{Message: message})
    if err != nil {
        log.Fatalf("client.UnaryEcho(_) = _, %v: ", err)
    }
    fmt.Println("UnaryEcho: ", resp.Message)
}

func main() {
    flag.Parse()
    cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithClientLogMode(aws.LogSigning))
    if err != nil {
        log.Fatalf("failed to load SDK configuration, %v", err)
    }

    pool, _ := x509.SystemCertPool()
    tlsConfig := &tls.Config{
        RootCAs: pool,
    }

    authority, _, _ := strings.Cut(*addr, ":") // Remove the port from the addr
    opts := []grpc.DialOption{
        grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),

        // Lattice needs both the Authority to be set (without a port), and the SigV4 signer
        grpc.WithAuthority(authority),
        grpc.WithPerRPCCredentials(NewSigV4GrpcSigner("vpc-lattice-svcs", *region, cfg.Credentials)),
    }

    conn, err := grpc.Dial(*addr, opts...)

    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    rgc := ecpb.NewEchoClient(conn)

    callUnaryEcho(rgc, "hello world")
}
```