

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

# GraphQL API를 보호하기 위한 권한 부여 및 인증 구성
<a name="security-authz"></a>

AWS AppSync는 GraphQL APIs를 보호하기 위해 API 키, Lambda, IAM, OpenID Connect 및 Cognito 사용자 풀과 같은 권한 부여 유형을 제공합니다. 각 옵션은 서로 다른 보안 방법을 제공합니다.

1. **API 키 권한 부여**: 인증되지 않은 API에 대한 스로틀링을 제어하여 간단한 보안 옵션을 제공합니다.

1. **Lambda 권한 부여**: 함수 입력 및 출력을 자세히 설명하는 사용자 지정 권한 부여 로직을 활성화합니다.

1. **IAM 권한 부여**: AWS의 서명 버전 4 서명 프로세스를 활용하여 IAM 정책을 통해 세분화된 액세스 제어를 허용합니다.

1. **OpenID Connect 권한 부여**: 사용자 인증을 위해 OIDC 준수 서비스와 통합됩니다.

1. **Cognito 사용자 풀**: Cognito의 사용자 관리 기능을 사용하여 그룹 기반 액세스 제어를 구현합니다.

## 권한 부여 유형
<a name="authorization-types"></a>

애플리케이션이 AWS AppSync GraphQL API와 상호 작용하도록 승인하는 방법에는 5가지가 있습니다. AWS AppSync API 또는 CLI 호출에서 다음 권한 부여 유형 값 중 하나를 지정하여 사용하는 권한 부여 유형을 지정합니다.
+   
** `API_KEY` **  
API 키를 사용하는 경우
+   
** `AWS_LAMBDA` **  
 AWS Lambda 함수를 사용하는 경우.
+   
** `AWS_IAM` **  
 AWS Identity and Access Management ([IAM](https://aws.amazon.com/iam/)) 권한을 사용하는 경우.
+   
** `OPENID_CONNECT` **  
OpenID Connect 공급자를 사용하는 경우
+   
** `AMAZON_COGNITO_USER_POOLS` **  
Amazon Cognito 사용자 풀을 사용하는 경우

이러한 기본 권한 부여 유형은 대부분의 개발자에게 유용합니다. 추가 고급 사용 사례를 보려면 콘솔, CLI 및 AWS CloudFormation을 통해 추가 권한 부여 모드를 추가할 수 있습니다. 추가 권한 부여 모드의 경우 AWS AppSync는 위에 나열된 값(즉, , `API_KEY`, `AWS_LAMBDA`, 및 `AWS_IAM``OPENID_CONNECT``AMAZON_COGNITO_USER_POOLS`)을 취하는 권한 부여 유형을 제공합니다.

`API_KEY`, `AWS_LAMBDA` 또는 `AWS_IAM`을 주 또는 기본 권한 부여 유형으로 지정하면 추가 권한 부여 모드 중 하나로 다시 지정할 수 없습니다. 마찬가지로, 추가 권한 부여 모드 내에서는 `API_KEY`, `AWS_LAMBDA` 또는 `AWS_IAM`을 복제할 수 없습니다. 여러 개의 Amazon Cognito 사용자 풀 및 OpenID Connect 공급자를 사용할 수 있습니다. 하지만 기본 권한 부여 모드와 추가 권한 부여 모드 중 하나 간에 중복 Amazon Cognito 사용자 풀 또는 OpenID Connect 공급자를 사용할 수 없습니다. 해당 구성 정규식을 사용하여 Amazon Cognito 사용자 풀 또는 OpenID Connect 공급자에 대해 다른 클라이언트를 지정할 수 있습니다.

API 구성에 대한 변경 사항을 저장하면가 변경 사항을 전파하기 AWS AppSync 시작합니다. 구성 변경이 전파될 때까지는 AWS AppSync 계속해서 이전 구성의 콘텐츠를 제공합니다. 구성 변경이 전파되면 AWS AppSync 즉시가 새 구성을 기반으로 콘텐츠를 제공하기 시작합니다. AWS AppSync 가 API에 대한 변경 사항을 전파하는 동안 API가 이전 구성 또는 새 구성을 기반으로 콘텐츠를 제공하고 있는지 확인할 수 없습니다.

## API\$1KEY 권한 부여
<a name="api-key-authorization"></a>

인증되지 않은 API에는 인증된 API보다 더 엄격한 조절이 필요합니다. 인증되지 않은 GraphQL 엔드포인트에 대한 조절을 제어하는 한 가지 방법은 API 키를 사용하는 것입니다. API 키는 애플리케이션에서 인증되지 않은 GraphQL 엔드포인트를 생성할 때 AWS AppSync 서비스에 의해 생성되는 하드 코딩된 값입니다. 콘솔, CLI 또는 [AWS AppSync API 참조](https://docs.aws.amazon.com/appsync/latest/APIReference/)에서 API 키를 교체할 수 있습니다.

------
#### [ Console ]

1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

   1. **API 대시보드**에서 GraphQL API를 선택합니다.

   1. **사이드바**에서 **설정**을 선택합니다.

1. **기본 권한 부여 모드**에서 **API 키**를 선택합니다.

1. **API 키** 테이블에서 **API 키 추가**를 선택합니다.

   테이블에 새 API 키가 생성됩니다.

   1. 이전 API 키를 삭제하려면 테이블에서 API 키를 선택한 다음 **삭제**를 선택합니다.

1. 페이지 하단에서 [**Save(저장하기)**]를 선택합니다.

------
#### [ CLI ]

1. 아직 구성하지 않은 경우 AWS CLI에 대한 액세스를 구성합니다. 자세한 정보는 [구성 기본 사항](https://docs.aws.amazon.com//cli/latest/userguide/cli-configure-quickstart.html)을 참조하세요.

1. [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-graphql-api.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-graphql-api.html) 명령을 실행하여 GraphQL API 객체를 생성합니다.

   이 특정 명령에 대해 두 개의 파라미터를 입력해야 합니다.

   1. GraphQL API의 `api-id`.

   1. API의 새 `name`. 동일한 `name`을 사용할 수 있습니다.

   1. `API_KEY`로 사용될 `authentication-type`.
**참고**  
필수로 구성해야 하지만 일반적으로 CLI 구성 값으로 기본 설정되는 `Region`과 같은 다른 파라미터도 있습니다.

   예를 들어 명령은 다음과 같을 수 있습니다.

   ```
   aws appsync update-graphql-api --api-id abcdefghijklmnopqrstuvwxyz --name TestAPI --authentication-type API_KEY
   ```

   CLI에서 출력이 반환됩니다. 다음은 JSON의 예입니다.

   ```
   {
       "graphqlApi": {
           "xrayEnabled": false,
           "name": "TestAPI",
           "authenticationType": "API_KEY",
           "tags": {},
           "apiId": "abcdefghijklmnopqrstuvwxyz",
           "uris": {
               "GRAPHQL": "https://s8i3kk3ufhe9034ujnv73r513e.appsync-api.us-west-2.amazonaws.com/graphql",
               "REALTIME": "wss://s8i3kk3ufhe9034ujnv73r513e.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
           },
           "arn": "arn:aws:appsync:us-west-2:348581070237:apis/abcdefghijklmnopqrstuvwxyz"
       }
   }
   ```

------

API 키는 최대 365일 동안 구성할 수 있으며 기존 만료 날짜를 해당일부터 최장 365일 더 연장할 수 있습니다. API 키는 개발용 또는 퍼블릭 API를 노출해도 안전한 사용 사례에 권장됩니다.

클라이언트에서 API 키는 헤더 `x-api-key`가 지정합니다.

예를 들어, `API_KEY`가 `'ABC123'`인 경우 다음과 같이 `curl` 을 통해 GraphQL 쿼리를 보낼 수 있습니다.

```
$ curl -XPOST -H "Content-Type:application/graphql" -H "x-api-key:ABC123" -d '{ "query": "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
```

## AWS\$1LAMBDA 권한 부여
<a name="aws-lambda-authorization"></a>

 AWS Lambda 함수를 사용하여 자체 API 권한 부여 로직을 구현할 수 있습니다. Lambda 함수를 기본 또는 보조 권한 부여자로 사용할 수 있지만, Lambda 권한 부여 함수는 API당 하나만 있을 수 있습니다. 권한 부여를 위해 Lambda 함수를 사용하는 경우 다음이 적용됩니다.
+ API에 `AWS_LAMBDA` 및 `AWS_IAM` 권한 부여 모드가 활성화되어 있는 경우 SigV4 서명을 `AWS_LAMBDA` 권한 부여 토큰으로 사용할 수 없습니다.
+ API에 `AWS_LAMBDA` 및 `OPENID_CONNECT` 권한 부여 모드 또는 `AMAZON_COGNITO_USER_POOLS` 권한 부여 모드가 활성화되어 있는 경우 OIDC 토큰을 `AWS_LAMBDA` 인증 토큰으로 사용할 수 없습니다. 참고로 OIDC 토큰은 보유자 체계일 수 있습니다.
+ Lambda 함수는 해석기에 대해 5MB를 초과하는 컨텍스트 데이터를 반환해서는 안 됩니다.

예를 들어 권한 부여 토큰이 `'ABC123'`인 경우 다음과 같이 curl을 통해 GraphQL 쿼리를 보낼 수 있습니다.

```
$ curl -XPOST -H "Content-Type:application/graphql" -H "Authorization:ABC123" -d '{ "query":
         "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
```

Lambda 함수는 각 쿼리 또는 변형 전에 호출됩니다. API ID 및 인증 토큰을 기반으로 반환 값을 캐시할 수 있습니다. Lambda 권한 부여자 응답이 1,048,576바이트 미만인 경우 AWS AppSync는 후속 요청에 대한 응답을 캐싱합니다. Lambda 권한 부여자 응답이 1,048,576바이트 이상인 경우 AWS AppSync는 응답을 캐싱하지 않고 각 수신 요청에 대해 Lambda 권한 부여자를 호출합니다. 성능을 최적화하고 Lambda 간접 호출 비용을 최소화하려면 Lambda 권한 부여자 응답을 1,048,576바이트로 제한하는 것이 좋습니다. 기본적으로 캐싱은 켜져 있지 않지만 API 수준에서 활성화하거나 함수의 반환 값에 `ttlOverride` 값을 설정하여 활성화할 수 있습니다.

필요한 경우 함수를 호출하기 전에 권한 부여 토큰의 유효성을 검사하는 정규식을 지정할 수 있습니다. 이러한 정규식은 함수를 호출하기 전에 권한 부여 토큰의 형식이 올바른지 확인하는 데 사용됩니다. 이 정규식과 일치하지 않는 토큰을 사용하는 모든 요청은 자동으로 거부됩니다.

권한 부여에 사용되는 Lambda 함수를 AWS AppSync 호출`appsync.amazonaws.com`하려면에 대한 보안 주체 정책을 적용해야 합니다. 이 작업은 AWS AppSync 콘솔에서 자동으로 수행됩니다. AWS AppSync 콘솔은 정책을 제거*하지* 않습니다. Lambda 함수에 정책을 연결하는 방법에 대한 자세한 내용은 AWS Lambda 개발자 안내서의 [리소스 기반 정책을](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke) 참조하세요.

지정하는 Lambda 함수는 다음과 같은 형태의 이벤트를 수신합니다.

```
{
    "authorizationToken": "ExampleAUTHtoken123123123",
    "requestContext": {
        "apiId": "aaaaaa123123123example123",
        "accountId": "111122223333",
        "requestId": "f4081827-1111-4444-5555-5cf4695f339f",
        "queryString": "mutation CreateEvent {...}\n\nquery MyQuery {...}\n",
        "operationName": "MyQuery",
        "variables": {}
    }
    "requestHeaders": {
        application request headers
    }
}
```

`event` 객체에는 애플리케이션 클라이언트에서 요청으로 전송된 헤더가 포함됩니다 AWS AppSync.

권한 부여 함수는 요청이 권한 부여되었는지 여부를 나타내는 부울`isAuthorized`인 이상을 반환해야 합니다.는 Lambda 권한 부여 함수에서 반환된 다음 키를 AWS AppSync 인식합니다.

**참고**  
`requestContext` WebSocket 연결 작업에 대한 `operationName`의 값은에 의해 "`DeepDish:Connect`" AWS AppSync 로 설정됩니다.

### 함수 목록
<a name="aws-lambda-authorization-list"></a>

`isAuthorized`(부울, 필수)  
`authorizationToken`의 값이 GraphQL API를 호출할 수 있는 권한이 있는지 여부를 나타내는 부울 값입니다.  
이 값이 참이면 GraphQL API가 계속 실행됩니다. 이 값이 거짓이면 `UnauthorizedException`이 발생합니다.

`deniedFields`(문자열 목록, 선택 사항)  
해석기에서 값이 반환된 경우에도 문자열 목록이 `null`로 강제 변경됩니다.  
각 항목은 `arn:aws:appsync:us-east-1:111122223333:apis/GraphQLApiId/types/TypeName/fields/FieldName` 형식 또는 축약된 `TypeName.FieldName` 형식의 정규화된 필드 ARN입니다. 두 API가 Lambda 함수 권한 부여자를 공유하며 두 API의 공통 유형과 필드 간에 모호성이 있을 수 있는 경우 전체 ARN 형식을 사용해야 합니다.

`resolverContext`(JSON 객체, 선택 사항)  
해석기 템플릿에 `$ctx.identity.resolverContext`로 표시되는 JSON 객체입니다. 예를 들어 해석기에서 다음 구조를 반환하는 경우:  

```
{
  "isAuthorized":true
  "resolverContext": {
    "banana":"very yellow",
    "apple":"very green" 
  }
}
```
해석기 템플릿의 `ctx.identity.resolverContext.apple` 값은 ‘`very green`’입니다. `resolverContext` 객체는 키-값 쌍만 지원합니다. 중첩 키는 지원되지 않습니다.  
이 JSON 객체의 총 크기는 5MB를 초과할 수 없습니다.

`ttlOverride`(정수, 선택 사항)  
응답을 캐시해야 하는 시간(초)입니다. 반환된 값이 없으면 API의 값이 사용됩니다. 이 값이 0이면 응답이 캐시되지 않습니다.

Lambda 권한 부여자의 표준 제한 시간은 10초이지만 트래픽이 가장 많은 조건에서는 더 일찍 제한 시간이 초과될 수 있습니다. API의 성능을 확장하려면 최대한 짧은 시간(1초 미만) 내에 실행할 함수를 설계하는 것이 좋습니다.

다중 AWS AppSync APIs 단일 인증 Lambda 함수를 공유할 수 있습니다. 교차 계정 권한 부여자 사용은 허용되지 않습니다.

여러 API 간에 권한 부여 함수를 공유하는 경우, 축약된 형식의 필드 이름(`typename.fieldname`)이 의도치 않게 필드를 숨길 수 있다는 점에 유의하세요. `deniedFields` 필드의 모호성을 없애려면 `arn:aws:appsync:region:accountId:apis/GraphQLApiId/types/typeName/fields/fieldName` 형식으로 명확한 필드 ARN을 지정하세요.

Lambda 함수를 AWS AppSync의 기본 권한 부여 모드로 추가하려면 다음을 따르세요.

------
#### [ Console ]

1.  AWS AppSync 콘솔에 로그인하고 업데이트하려는 API로 이동합니다.

1. API의 설정 페이지로 이동합니다.

   API 수준 권한 부여를 **AWS Lambda**으로 변경합니다.

1. API 호출을 승인할 AWS 리전 및 Lambda ARN을 선택합니다.
**참고**  
적절한 보안 주체 정책이 자동으로 추가되어 AWS AppSync 에서 Lambda 함수를 직접적으로 호출할 수 있습니다.

1. 필요한 경우 응답 TTL 및 토큰 검증 정규식을 설정합니다.

------
#### [ AWS CLI ]

1. 사용 중인 Lambda 함수에 다음 정책을 연결합니다.

   ```
   aws lambda add-permission --function-name "my-function" --statement-id "appsync" --principal appsync.amazonaws.com --action lambda:InvokeFunction --output text 
   ```
**중요**  
함수 정책을 단일 GraphQL API로 고정하려면 다음 명령을 실행하세요.  

   ```
   aws lambda add-permission --function-name “my-function” --statement-id “appsync” --principal appsync.amazonaws.com --action lambda:InvokeFunction --source-arn “<my AppSync API ARN>” --output text
   ```

1. 지정된 Lambda 함수 ARN을 권한 부여자로 사용하도록 AWS AppSync API를 업데이트합니다.

   ```
   aws appsync update-graphql-api --api-id example2f0ur2oid7acexample --name exampleAPI --authentication-type AWS_LAMBDA --lambda-authorizer-config authorizerUri="arn:aws:lambda:us-east-2:111122223333:function:my-function"
   ```
**참고**  
토큰 정규식과 같은 기타 구성 옵션을 포함할 수도 있습니다.

------

다음 예는 Lambda 함수가 AWS AppSync 권한 부여 메커니즘으로 사용될 때 가질 수 있는 다양한 인증 및 결함 상태를 보여주는 Lambda 함수를 설명합니다.

```
def handler(event, context):
  # This is the authorization token passed by the client
  token = event.get('authorizationToken')
  # If a lambda authorizer throws an exception, it will be treated as unauthorized. 
  if 'Fail' in token:
    raise Exception('Purposefully thrown exception in Lambda Authorizer.')

  if 'Authorized' in token and 'ReturnContext' in token:
    return {
      'isAuthorized': True,
      'resolverContext': {
        'key': 'value'
      }
    }

  # Authorized with no f
  if 'Authorized' in token:
    return {
      'isAuthorized': True
    }
  # Partial authorization
  if 'Partial' in token:
    return {
      'isAuthorized': True,
      'deniedFields':['user.favoriteColor']
    }
  if 'NeverCache' in token:
    return {
      'isAuthorized': True,
      'ttlOverride': 0
    }
  if 'Unauthorized' in token:
    return {
      'isAuthorized': False
    }
  # if nothing is returned, then the authorization fails. 
  return {}
```

### SigV4 및 OIDC 토큰 권한 부여 제한 방지
<a name="aws-lambda-authorization-create-new-auth-token"></a>

다음 방법을 사용하여 특정 권한 부여 모드가 활성화된 경우 SigV4 서명 또는 OIDC 토큰을 Lambda 권한 부여 토큰으로 사용할 수 없는 문제를 방지할 수 있습니다.

 AWS AppSync의 API에 대해 `AWS_IAM` 및 `AWS_LAMBDA` 권한 부여 모드가 활성화되어 있을 때 SigV4 서명을 Lambda 권한 부여 토큰으로 사용하려면 다음을 따르세요.
+ 새 Lambda 권한 부여 토큰을 생성하려면 SigV4 서명에 임의의 접미사 또는 접두사를 추가하세요.
+ 원본 SigV4 서명을 검색하려면 Lambda 권한 부여 토큰에서 임의의 접두사 또는 접미사를 제거하여 Lambda 함수를 업데이트하세요. 그런 다음 원본 SigV4 서명을 인증에 사용합니다.

권한 부여 모드 또는 `AMAZON_COGNITO_USER_POOLS` 및 권한 부여 모드가 AWS AppSync API에 대해 활성화된 경우 OIDC 토큰을 Lambda `AWS_LAMBDA` 권한 `OPENID_CONNECT` 부여 토큰으로 사용하려면 다음을 수행합니다.
+ 새 Lambda 권한 부여 토큰을 생성하려면 OIDC 토큰에 임의의 접미사 또는 접두사를 추가하세요. Lambda 권한 부여 토큰에는 보유자 체계 접두사를 포함할 수 없습니다.
+ 원본 OIDC 토큰을 검색하려면 Lambda 권한 부여 토큰에서 임의의 접두사 또는 접미사를 제거하여 Lambda 함수를 업데이트하세요. 그런 다음 원본 OIDC 토큰을 인증에 사용합니다.

## AWS\$1IAM 권한 부여
<a name="aws-iam-authorization"></a>

이 권한 부여 유형은 GraphQL API에 대해 [AWS 서명 버전 4 서명 프로세스](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)를 적용합니다. [IAM](https://aws.amazon.com/iam/)(Identity and Access Management) 액세스 정책을 권한 부여 유형과 연결할 수 있습니다. 애플리케이션에서는 액세스 키(액세스 키 ID와 비밀 액세스 키로 구성됨)를 사용하거나 Amazon Cognito 연동 자격 증명에서 제공한 단기 임시 보안 인증을 사용하여 이 연결을 활용할 수 있습니다.

모든 데이터 작업을 수행하기 위한 액세스 권한이 있는 역할이 필요한 경우:

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

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "appsync:GraphQL"
         ],
         "Resource": [
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/*"
         ]
      }
   ]
}
```

------

AppSync 콘솔의 기본 API 목록 페이지에 있는 API 이름 바로 아래에서 `YourGraphQLApiId`를 찾을 수 있습니다. 또한 CLI `aws appsync list-graphql-apis`를 사용하여 검색할 수도 있습니다.

특정 GraphQL 작업으로 액세스를 제한하려는 경우 루트 `Query`, `Mutation` 및 `Subscription` 필드에 대해 액세스를 제한할 수 있습니다.

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

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "appsync:GraphQL"
         ],
         "Resource": [
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-1>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-2>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Mutation/fields/<Field-1>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Subscription/fields/<Field-1>"
         ]
     }
   ]
}
```

------

예를 들어, 다음 스키마를 가정하고 모든 게시글 가져오기에 대한 액세스를 제한하려고 합니다.

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
}
```

(예를 들어 Amazon Cognito 자격 증명 풀에 연결할 수 있는) 역할에 해당하는 IAM 정책은 다음과 같습니다.

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
            "appsync:GraphQL"
            ],
            "Resource": [
                "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/posts"
            ]
        }
    ]
}
```

------

## OPENID\$1CONNECT 권한 부여
<a name="openid-connect-authorization"></a>

이 권한 부여 유형은 OIDC 호환 서비스에서 제공하는 [OpenID 연결](https://openid.net/specs/openid-connect-core-1_0.html)(OIDC) 토큰을 강제로 적용합니다. 애플리케이션에서는 OIDC 공급자가 액세스 제어를 위해 정의한 사용자 및 권한을 활용합니다.

발급자 URL은 AWS AppSync에 제공하는 유일한 필수 구성 값입니다(예: `https://auth.example.com`). 이 URL은 HTTPS를 통해 주소를 지정할 수 있어야 합니다. AWS AppSync는 발급자 URL`/.well-known/openid-configuration`에 추가되고 OpenID Connect 검색 사양에 `https://auth.example.com/.well-known/openid-configuration` 따라에서 OpenID 구성을 찾습니다. [OpenID ](https://openid.net/specs/openid-connect-discovery-1_0.html) 이 URL에서 [RFC5785](https://tools.ietf.org/html/rfc5785) 호환 JSON 문서를 검색해야 합니다. 이 JSON 문서에는 서명 `jwks_uri` 키가 있는 JSON 웹 키 세트(JWKS) 문서를 가리키는 키가 포함되어야 합니다. AWS AppSync에서는 JWKS에 `kty` 및의 JSON 필드가 포함되어야 합니다`kid`.

AWS AppSync는 다양한 서명 알고리즘을 지원합니다.


| 서명 알고리즘 | 
| --- | 
| RS256 | 
| RS384 | 
| RS512 | 
| PS256 | 
| PS384 | 
| PS512 | 
| HS256 | 
| HS384 | 
| HS512 | 
| ES256 | 
| ES384 | 
| ES512 | 

RSA 알고리즘을 사용하는 것이 좋습니다. 공급자가 발행하는 토큰에는 토큰이 발행된 시간(`iat`)이 포함되어 있어야 하며 토큰이 인증된 시간(`auth_time`)이 포함될 수 있습니다. 추가 확인을 위해 발행된 시간에 대한 TTL 값(`iatTTL`)과 OpenID Connect 구성의 인증 시간(`authTTL`)을 제공할 수 있습니다. 공급자가 여러 애플리케이션을 인증하면 클라이언트 ID별로 인증하는 데 사용되는 정규식(`clientId`)도 제공할 수 있습니다. OpenID Connect 구성에이 있는 경우 AWS AppSync`clientId`는가 토큰의 `aud` 또는 클레임과 `clientId` 일치하도록 요구하여 `azp` 클레임을 검증합니다.

여러 클라이언트 ID를 검증하려면 정규식에서는 'or'인 파이프라인 연산자('\$1')를 사용합니다. 예를 들어 OIDC 애플리케이션에 클라이언트 ID가 각각 0A1S2D, 1F4G9H, 1J6L4B, 6GS5MG인 4개의 클라이언트가 있는 경우, 앞쪽의 3개 클라이언트 ID만 검증하려면 클라이언트 ID 필드에 1F4G9H\$11J6L4B\$16GS5MG를 배치합니다.

API가 여러 권한 부여 유형으로 구성된 경우 AWS AppSync는 요청 헤더의 JWT 토큰에 있는 발급자(iss 클레임)를 API 구성에 지정된 발급자 URL과 비교하여 검증합니다. 그러나 API가 OPENID\$1CONNECT 권한 부여로만 구성된 경우 AWS AppSync는이 발급자 URL 검증 단계를 건너뜁니다.

## AMAZON\$1COGNITO\$1USER\$1POOLS 권한 부여
<a name="amazon-cognito-user-pools-authorization"></a>

이 권한 부여 유형은 Amazon Cognito 사용자 풀에서 제공한 OIDC 토큰을 적용합니다. 애플리케이션은 사용자 풀과 다른 AWS 계정의 사용자 풀 모두에 있는 사용자 및 그룹을 활용하여 이를 GraphQL 필드와 연결하여 액세스를 제어할 수 있습니다.

Amazon Cognito 사용자 풀을 사용하는 경우 사용자가 속한 그룹을 생성할 수 있습니다. 이 정보는 애플리케이션이 GraphQL 작업을 전송할 때 권한 부여 헤더의 AWS AppSync로 보내는 JWT 토큰으로 인코딩됩니다. 스키마에 GraphQL 명령을 사용하여 어떤 그룹이 필드의 어떤 해석기를 호출할 수 있는지 제어하여 고객에게 보다 정확하게 제어되는 액세스 권한을 제공할 수 있습니다.

예를 들어 다음과 같은 GraphQL 스키마가 있다고 가정하겠습니다.

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
}
...
```

Amazon Cognito 사용자 풀에 블로거 및 독자라는 두 가지 그룹이 있고 새 항목을 추가할 수 없도록 독자를 제한하려는 경우 스키마는 다음과 같아야 합니다.

```
schema {
   query: Query
   mutation: Mutation
}
```

```
type Query {
   posts:[Post!]!
   @aws_auth(cognito_groups: ["Bloggers", "Readers"])
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
   @aws_auth(cognito_groups: ["Bloggers"])
}
...
```

액세스에 대해 특정 권한 부여 또는 거부 전략을 기본적으로 지정하려는 경우 `@aws_auth` 명령을 생략할 수 있습니다. 콘솔 또는 다음 CLI 명령을 통해 GraphQL API를 생성하는 경우 사용자 풀 구성에서 권한 부여 또는 거부 전략을 지정할 수 있습니다.

```
$ aws appsync --region us-west-2 create-graphql-api --authentication-type AMAZON_COGNITO_USER_POOLS  --name userpoolstest --user-pool-config '{ "userPoolId":"test", "defaultEffect":"ALLOW", "awsRegion":"us-west-2"}'
```

## 추가 권한 부여 모드 사용
<a name="using-additional-authorization-modes"></a>

추가 권한 부여 모드를 추가할 때 AWS AppSync GraphQL API 수준(즉, `GraphqlApi` 객체에서 직접 구성할 수 있는 `authenticationType` 필드)에서 권한 부여 설정을 직접 구성할 수 있으며 스키마의 기본값 역할을 합니다. 다시 말해서, 특정 지시문이 없는 모든 유형은 API 수준 권한 부여 설정을 전달해야 합니다.

스키마 수준에서 스키마에 대한 지시문을 사용하여 추가 권한 부여 모드를 지정할 수 있습니다 스키마의 개별 필드에서 권한 부여 모드를 지정할 수 있습니다. 예를 들어, `API_KEY` 권한 부여의 경우 스키마 객체 유형 정의/필드에서 `@aws_api_key`를 사용합니다. 스키마 필드 및 객체 유형 정의에서는 다음 지시문이 지원됩니다.
+  `@aws_api_key` - 필드에 `API_KEY` 권한이 부여되도록 지정합니다.
+  `@aws_iam` - 필드에 `AWS_IAM` 권한이 부여되도록 지정합니다.
+  `@aws_oidc` - 필드에 `OPENID_CONNECT` 권한이 부여되도록 지정합니다.
+  `@aws_cognito_user_pools` - 필드에 `AMAZON_COGNITO_USER_POOLS` 권한이 부여되도록 지정합니다.
+  `@aws_lambda` - 필드에 `AWS_LAMBDA` 권한이 부여되도록 지정합니다.

`@aws_auth` 지시문을 추가 권한 부여 모드와 함께 사용할 수 없습니다. `@aws_auth`는 추가 권한 부여 모드가 없는 `AMAZON_COGNITO_USER_POOLS` 권한 부여의 컨텍스트에서만 작동합니다. 하지만 샘플 인수를 사용하여 `@aws_auth` 지시문 대신에 `@aws_cognito_user_pools` 지시문을 사용할 수 있습니다. 두 지시문 간의 주요 차이점은 모든 필드와 객체 유형 정의에서 `@aws_cognito_user_pools`를 지정할 수 있다는 것입니다.

추가 권한 부여 모드가 작동하는 방식과 스키마에서 추가 권한 부여 모드를 지정할 수 있는 방법을 이해하기 위해 다음 스키마를 살펴보겠습니다.

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   getPost(id: ID): Post
   getAllPosts(): [Post]
   @aws_api_key
}

type Mutation {
   addPost(
      id: ID!
      author: String!
      title: String!
      content: String!
      url: String!
   ): Post!
}

type Post @aws_api_key @aws_iam {
   id: ID!
   author: String
   title: String
   content: String
   url: String
   ups: Int!
   downs: Int!
   version: Int!
}
...
```

이 스키마의 경우 `AWS_IAM`가 AWS AppSync GraphQL API의 기본 권한 부여 유형이라고 가정합니다. 다시 말해서, 지시문이 없는 필드는 `AWS_IAM`을 사용하여 보호됩니다. 예를 들어, `Query` 유형에서 `getPost` 필드의 경우에도 마찬가지입니다. 스키마 지시문을 사용하면 두 개 이상의 권한 부여 모드를 사용할 수 있습니다. 예를 들어를 AWS AppSync GraphQL API에서 추가 권한 부여 모드로 `API_KEY` 구성하고 `@aws_api_key` 지시문을 사용하여 필드를 표시할 수 있습니다(예: `getAllPosts`이 예제). 지시문은 필드 수준에서 작동하므로 `API_KEY`에 `Post` 유형에 대한 액세스 권한도 부여해야 합니다. 지시문으로 `Post` 유형의 각 필드에 표시하거나 `@aws_api_key` 지시문으로 `Post` 유형에 표시하여 이렇게 할 수 있습니다.

`Post` 유형의 필드에 대한 액세스를 한층 더 제한하려면 다음과 같이 `Post` 유형의 개별 필드에 대해 지시문을 사용할 수 있습니다.

예를 들어, `@aws_iam` 지시문을 사용하여 `restrictedContent` 필드를 `Post` 유형에 추가하고 이 필드에 대한 액세스를 제한할 수 있습니다. `AWS_IAM` 권한이 있는 요청은 `restrictedContent`에 액세스할 수 있지만, `API_KEY` 요청은 액세스할 수 없습니다.

```
type Post @aws_api_key @aws_iam{
   id: ID!
   author: String
   title: String
   content: String
   url: String
   ups: Int!
   downs: Int!
   version: Int!
   restrictedContent: String!
   @aws_iam
}
...
```

## 세분화된 액세스 제어
<a name="fine-grained-access-control"></a>

앞선 정보는 특정 GraphQL 필드에 대한 액세스 제한 또는 부여 방법을 설명합니다. 특정 조건을 기준으로(예를 들어, 호출하는 사용자 및 해당 사용자가 데이터를 소유하는지 여부를 기준으로) 데이터에 대한 액세스 제어를 설정하려는 경우 해석기에서 매핑 템플릿을 사용할 수 있습니다. 또한 [필터링 정보](#aws-appsync-filtering-information)에서 설명하는 보다 복잡한 비즈니스 로직을 수행할 수도 있습니다.

이 섹션에서는 DynamoDB 해석기 매핑 템플릿을 사용하여 데이터에 대한 액세스 제어를 설정하는 방법을 보여줍니다.

계속 진행하기 전에 AWS AppSync의 매핑 템플릿에 대해 잘 모르는 경우 [해석기 매핑 템플릿 참조](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference) 및 [DynamoDB에 대한 해석기 매핑 템플릿 참조](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb)를 검토하면 좋습니다.

DynamoDB를 사용하는 다음 예에서는 이전 블로그 게시 스키마를 사용하고 게시글을 작성한 사용자만 해당 게시글을 편집할 수 있도록 허용한다고 가정합니다. 평가 프로세스는 사용자가 예를 들어, Amazon Cognito 사용자 풀을 사용하여 애플리케이션에서 자격 증명을 얻은 다음 GraphQL 작업의 일부로 해당 자격 증명을 전달하도록 하는 과정입니다. 그런 다음 매핑 템플릿은 조건문에서 자격 증명(예: 사용자 이름)의 값을 대체하고 이 값을 데이터베이스의 값과 비교합니다.

![\[Diagram showing authentication flow from user login to database operation using AWS 서비스.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/FGAC.png)


이 기능을 추가하려면 다음과 같이 GraphQL 필드 `editPost`를 추가합니다.

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   editPost(id:ID!, title:String, content:String):Post
   addPost(id:ID!, title:String!):Post!
}
...
```

`editPost`의 해석기 매핑 템플릿(이 단원의 끝에 나오는 예 참조)은 데이터 스토어에 대한 로직 점검을 수행해 게시글을 생성한 사용자만 해당 게시글을 편집하도록 해야 합니다. 이 작업은 편집 작업이기 때문에 DynamoDB에서는 `UpdateItem`에 해당합니다. 이 작업을 수행하기 전에 사용자 자격 검증을 통해 전달된 컨텍스트로 조건 검사를 수행할 수 있습니다. 이 컨텍스트는 다음 값을 가지는 `Identity` 객체에 저장됩니다.

```
{
   "accountId" : "12321434323",
   "cognitoIdentityPoolId" : "",
   "cognitoIdentityId" : "",
   "sourceIP" : "",
   "caller" : "ThisistheprincipalARN",
   "username" : "username",
   "userArn" : "Sameasabove"
}
```

DynamoDB`UpdateItem` 직접 호출 시 이 객체를 사용하려면 비교를 위해 테이블에 사용자 자격 증명 정보를 저장해야 합니다. 먼저, `addPost` 변형이 생성자를 저장해야 합니다. 그 다음으로, `editPost` 변형이 업데이트 전에 조건 검사를 수행해야 합니다.

다음은 사용자 ID를 `Author`열로 저장하는 `addPost`에 대한 해석기 코드의 예시입니다.

```
import { util, Context } from '@aws-appsync/utils';
import { put } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	const { id: postId, ...item } = ctx.args;
	return put({
		key: { postId },
		item: { ...item, Author: ctx.identity.username },
		condition: { postId: { attributeExists: false } },
	});
}

export const response = (ctx) => ctx.result;
```

`Author` 속성은 애플리케이션에서 가져온 `Identity` 객체의 속성으로 채워집니다.

마지막으로, 다음은 게시글을 작성한 사용자가 요청한 경우에만 블로그 게시글의 내용을 업데이트하는 `editPost`의 해석기 코드의 예시입니다.

```
import { util, Context } from '@aws-appsync/utils';
import { put } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	const { id, ...item } = ctx.args;
	return put({
		key: { id },
		item,
		condition: { author: { contains: ctx.identity.username } },
	});
}

export const response = (ctx) => ctx.result;
```

이 예시에서는 `UpdateItem`보다는 모든 값을 덮어쓰는 `PutItem`을 사용하지만, 동일한 개념이 `condition` 문 블록에 적용됩니다.

## 필터링 정보
<a name="aws-appsync-filtering-information"></a>

데이터 원본의 응답을 제어할 수 없는 경우가 있을 수 있지만 데이터 원본에 쓰기 또는 읽기 성공에 대한 불필요한 정보를 클라이언트에게 보내고 싶지 않습니다. 이러한 경우 응답 매핑 템플릿을 사용하여 정보를 필터링할 수 있습니다.

예를 들어, 블로그 게시물 DynamoDB 테이블에 대한 적절한 인덱스(예: `Author`에 대한 인덱스)가 없다고 가정해 보겠습니다. 다음 해석기를 사용할 수 있습니다.

```
import { util, Context } from '@aws-appsync/utils';
import { get } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	return get({ key: { ctx.args.id } });
}

export function response(ctx) {
	if (ctx.result.author === ctx.identity.username) {
		return ctx.result;
	}
	return null;
}
```

요청 핸들러는 발신자가 게시물을 만든 작성자가 아니더라도 항목을 가져옵니다. 이렇게 하면 모든 데이터가 반환되지 않도록 응답 핸들러는 발신자가 항목 작성자와 일치하는지 확인합니다. 호출자가 이 검사와 일치하지 않는 경우 null 응답만 반환됩니다.

## 데이터 원본 액세스
<a name="data-source-access"></a>

AWS AppSync는 Identity and Access Management([IAM](https://aws.amazon.com/iam/)) 역할 및 액세스 정책을 사용하여 데이터 소스와 통신합니다. 기존 역할을 사용하는 경우 AWS AppSync가 역할을 수임하려면 신뢰 정책을 추가해야 합니다. 신뢰 관계는 아래와 같아야 합니다.

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

****  

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

------

해당 역할에 대한 액세스 정책을 축소하여 권한을 필요한 최소한의 원본 집합에만 허용하는 것이 중요합니다. AppSync 콘솔을 사용하여 데이터 원본 및 역할을 생성하는 경우, 이 과정은 자동으로 수행됩니다. 그러나 IAM 콘솔의 내장 샘플 템플릿을 사용하여 AWS AppSync 콘솔 외부에서 역할을 생성하는 경우 리소스에서 권한 범위가 자동으로 축소되지 않으므로 애플리케이션을 프로덕션으로 이동하기 전에이 작업을 수행해야 합니다.

# 요청 및 응답을 보호하는 액세스 제어 사용 사례
<a name="security-authorization-use-cases"></a>

[보안](security-authz.md#aws-appsync-security) 단원에서는 API 보호를 위한 다양한 권한 부여 모드에 대해 알아보았으며 개념과 흐름을 이해할 수 있도록 세분화된 권한 부여 메커니즘을 소개했습니다. AWS AppSync를 사용하면 GraphQL 해석기 [매핑 템플릿을](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview) 사용하여 데이터에 대한 로직 전체 작업을 수행할 수 있으므로 사용자 자격 증명, 조건부 및 데이터 주입의 조합을 사용하여 읽기 또는 쓰기 시 데이터를 매우 유연한 방식으로 보호할 수 있습니다.

 AWS AppSync 해석기 편집에 익숙하지 않은 경우 [프로그래밍 가이드를](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide) 검토하세요.

## 개요
<a name="overview"></a>

지금까지는 시스템의 데이터에 대한 액세스 권한 부여가 [액세스 제어 매트릭스](https://en.wikipedia.org/wiki/Access_Control_Matrix)를 통해 수행되었으며, 이 매트릭스에서 행(리소스)과 열(사용자/역할)의 교차점이 부여되는 권한이었습니다.

AWS AppSync는 자체 계정의 리소스를 사용하고 GraphQL 요청 및 응답에 자격 증명(사용자/역할) 정보를 [컨텍스트 객체](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)로 스레드합니다.이 객체는 해석기에서 사용할 수 있습니다. 다시 말해서 해석기 로직에 따라 쓰기 또는 읽기 작업에 대한 권한을 적절히 부여할 수 있습니다. 이 로직이 리소스 수준에 있는 경우, 예를 들어 이름이 지정된 특정 사용자 또는 그룹만 특정 데이터베이스 행을 읽거나 쓸 수 있는 경우 해당 “권한 부여 메타데이터”를 저장해야 합니다. AWS AppSync는 데이터를 저장하지 않으므로 권한을 계산할 수 있도록이 권한 부여 메타데이터를 리소스와 함께 저장해야 합니다. 권한 부여 메타데이터는 일반적으로 **소유자** 또는 사용자/그룹 목록 같은 DynamoDB 테이블에 속성(열)입니다. 예를 들면 **Readers** 및 **Writers** 속성이 있을 수 있습니다.

다시 말해, 상위 수준에서는 데이터 원본의 개별 항목을 읽으려는 경우 해석기를 데이터 원본에서 읽어온 후 응답 템플릿에서 조건부 `#if () ... #end` 문을 수행할 수 있다는 뜻입니다. 이 확인은 일반적으로 읽기 작업에서 반환되는 권한 부여 메타데이터와 비교하여 멤버십을 확인하기 위해 `$context.identity`의 사용자 또는 그룹 값을 사용합니다. `Scan` 또는 `Query` 테이블에서 반환되는 목록과 같이 여러 레코드의 경우, 유사한 사용자 또는 그룹 값을 사용하여 작업의 일부로서 조건부 확인을 데이터 소스로 전송합니다.

데이터를 작성할 때와 마찬가지로 조건문을 작업(예: `PutItem` 또는 `UpdateItem`)에 적용하여 변형을 만드는 사용자나 그룹이 권한을 가지고 있는지 여부를 확인합니다. 이 조건문은 `$context.identity`의 값 하나를 여러 번 다시 사용하여 해당 리소스에 대한 권한 부여 메타데이터와 비교합니다. 요청 및 응답 템플릿 모두에 대해 클라이언트의 사용자 지정 헤더를 사용하여 검증 확인을 수행할 수도 있습니다.

## 데이터 읽기
<a name="reading-data"></a>

위에 요약된 바와 같이 확인을 수행할 권한 부여 메타데이터를 리소스와 함께 저장하거나 GraphQL 요청(자격 증명, 헤더 등)에 전달해야 합니다. 이를 설명하기 위해 아래에 나오는 DynamoDB 테이블이 있다고 가정하겠습니다.

![\[DynamoDB table with ID, Data, PeopleCanAccess, GroupsCanAccess, and Owner columns.\]](http://docs.aws.amazon.com/ko_kr/appsync/latest/devguide/images/auth.png)


기본 키는 `id`이며 액세스해야 할 데이터는 `Data`입니다. 다른 열은 승인을 위해 수행할 수 있는 확인의 예입니다. [DynamoDB에 대한 해석기 매핑 템플릿 참조](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb)에 설명된 대로 `Owner`는 `String`이고 `PeopleCanAccess` 및 `GroupsCanAccess`는 `String Sets`입니다.

[해석기 매핑 템플릿 개요](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)의 다이어그램은 응답 템플릿에 컨텍스트 객체는 물론 데이터 원본의 결과도 포함됨을 보여줍니다. 개별 항목의 GraphQL 쿼리의 경우 응답 템플릿을 사용하여 사용자에게 이러한 결과를 보도록 허용되었는지 여부를 확인하거나 아니면 권한 부여 오류 메시지를 반환할 수 있습니다. 이를 때로는 ‘권한 부여 필터’라고도 합니다. 스캔 또는 쿼리를 사용하는 GraphQL 쿼리 반환 목록의 경우, 요청 템플릿에 대한 확인을 수행하고 권한 부여 조건이 충족되는 경우에만 데이터를 반환하는 것이 더 바람직합니다. 구현은 다음과 같습니다.

1. GetItem - 개별 레코드에 대한 권한 부여 확인입니다. `#if() ... #end` 문을 사용하여 수행됩니다.

1. 스캔/쿼리 작업 - 권한 부여 확인이 `"filter":{"expression":...}` 문입니다. 일반적으로 같음(`attribute = :input`)을 확인하거나 목록에 값(`contains(attribute, :input)`)이 있는지 여부를 확인합니다.

\$12에서는 두 명령문의 `attribute`가 위의 예제의 `Owner`와 같은 테이블 내 레코드 열 이름을 나타냅니다. `#` 기호를 사용하여 이 이름을 별칭으로 지정하고 `"expressionNames":{...}`를 사용할 수 있지만, 필수는 아닙니다. `:input`은 데이터베이스 속성과 비교할 값에 대한 참조로, `"expressionValues":{...}`에서 정의합니다. 다음과 같은 예제가 표시됩니다.

### 사용 사례: 소유자에게 읽기 허용
<a name="use-case-owner-can-read"></a>

위의 테이블을 사용할 때, 개별 읽기 작업(`Owner == Nadia`)에 대해 `GetItem`일 때만 데이터를 반환하려는 경우 템플릿은 다음과 같습니다.

```
#if($context.result["Owner"] == $context.identity.username)
    $utils.toJson($context.result)
#else
    $utils.unauthorized()
#end
```

여기에 언급된 몇 가지 사항은 나머지 단원에서 재사용될 것입니다. 먼저 이 확인은 `$context.identity.username`을 사용하는데, 이 이름은 Amazon Cognito 사용자 풀이 사용되는 경우 친숙한 사용자 등록 이름이며 IAM이 사용되는 경우 사용자 자격 증명(Amazon Cognito 연동 자격 증명 포함)입니다. 고유한 'Amazon Cognito 자격 증명' 값(여러 위치에서 로그인을 연동할 때 유용함)과 같이 소유자에 대해 저장할 다른 값도 있으며, [해석기 매핑 템플릿 컨텍스트 참조](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)에서 사용 가능한 옵션을 검토해야 합니다.

두 번째, `$util.unauthorized()`를 사용한 else 조건 확인 응답은 완전히 선택 사항이지만 GraphQL API를 설계할 때 모범 사례로서 권장됩니다.

### 사용 사례: 특정 액세스 하드코딩
<a name="use-case-hardcode-specific-access"></a>

```
// This checks if the user is part of the Admin group and makes the call
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #if($group == "Admin")
        #set($inCognitoGroup = true)
    #end
#end
#if($inCognitoGroup)
{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "attributeValues" : {
        "owner" : $util.dynamodb.toDynamoDBJson($context.identity.username)
        #foreach( $entry in $context.arguments.entrySet() )
            ,"${entry.key}" : $util.dynamodb.toDynamoDBJson($entry.value)
        #end
    }
}
#else
    $utils.unauthorized()
#end
```

### 사용 사례: 결과 목록 필터링
<a name="use-case-filtering-a-list-of-results"></a>

이전 예에서는 단일 항목을 반환하므로 `$context.result`에 대해 확인을 직접 수행할 수 있었지만, 스캔과 같은 일부 작업은 `$context.result.items`에서 여러 항목을 반환합니다. 이 경우에는 권한 부여 필터를 수행하여 사용자에게 보기가 허용된 결과만 반환해야 합니다. `Owner` 필드에서 현재 Amazon Cognito IdentityID가 레코드에 대해 설정되었다고 가정해 보겠습니다. 이제 다음 응답 매핑 템플릿을 사용하여 사용자가 소유하는 레코드만 표시하도록 필터링할 수 있습니다.

```
#set($myResults = [])
#foreach($item in $context.result.items)
    ##For userpools use $context.identity.username instead
    #if($item.Owner == $context.identity.cognitoIdentityId)
        #set($added = $myResults.add($item))
    #end
#end
$utils.toJson($myResults)
```

### 사용 사례: 여러 사람에게 읽기 허용
<a name="use-case-multiple-people-can-read"></a>

또 한 가지 널리 사용되는 권한 부여 옵션은 사람 그룹에 데이터 읽기를 허용하는 것입니다. 아래 예에서는 GraphQL 쿼리를 실행하는 사용자가 `"filter":{"expression":...}` 세트에 나열되는 경우에만 `PeopleCanAccess`가 테이블 스캔에서 값을 반환합니다.

```
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": #if(${context.arguments.count}) $util.toJson($context.arguments.count) #else 20 #end,
    "nextToken": #if(${context.arguments.nextToken})  $util.toJson($context.arguments.nextToken) #else null #end,
    "filter":{
        "expression": "contains(#peopleCanAccess, :value)",
        "expressionNames": {
                "#peopleCanAccess": "peopleCanAccess"
        },
        "expressionValues": {
                ":value": $util.dynamodb.toDynamoDBJson($context.identity.username)
        }
    }
}
```

### 사용 사례: 그룹에 읽기 허용
<a name="use-case-group-can-read"></a>

마지막 사용 사례와 마찬가지로, 이 사용 사례에서는 하나 이상의 그룹 내 사람들만 데이터베이스의 특정 항목을 읽을 수 있습니다. `"expression": "contains()"` 작업의 사용도 비슷하지만, 이것은 설정된 멤버십에서 사용자가 속해 있을 수 있는 모든 그룹의 논리 OR입니다. 여기서는 사용자가 속한 각 그룹에 대해 아래 `$expression` 문을 작성한 다음 이 문을 필터에 전달합니다.

```
#set($expression = "")
#set($expressionValues = {})
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #set( $expression = "${expression} contains(groupsCanAccess, :var$foreach.count )" )
    #set( $val = {})
    #set( $test = $val.put("S", $group))
    #set( $values = $expressionValues.put(":var$foreach.count", $val))
    #if ( $foreach.hasNext )
    #set( $expression = "${expression} OR" )
    #end
#end
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": #if(${context.arguments.count}) $util.toJson($context.arguments.count) #else 20 #end,
    "nextToken": #if(${context.arguments.nextToken})  $util.toJson($context.arguments.nextToken) #else null #end,
    "filter":{
        "expression": "$expression",
        "expressionValues": $utils.toJson($expressionValues)
    }
}
```

## 데이터 쓰기
<a name="writing-data"></a>

변형에 대한 데이터 쓰기는 항상 요청 매핑 템플릿에서 제어됩니다. DynamoDB 데이터 원본의 경우, 핵심은 해당 테이블의 권한 부여 메타데이터를 확인하는 적정 `"condition":{"expression"...}"`을 사용하는 것입니다. [보안](security-authz.md#aws-appsync-security) 단원에 테이블의 `Author` 필드를 확인할 수 있는 예제를 제공했습니다. 이 단원의 사용 사례에서는 더 많은 사용 사례를 살펴봅니다.

### 사용 사례: 여러 소유자
<a name="use-case-multiple-owners"></a>

앞의 예제 테이블 다이어그램을 사용하면서, `PeopleCanAccess` 목록을 가정해 보겠습니다.

```
{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "update" : {
        "expression" : "SET meta = :meta",
        "expressionValues": {
            ":meta" : $util.dynamodb.toDynamoDBJson($ctx.args.meta)
        }
    },
    "condition" : {
        "expression"       : "contains(Owner,:expectedOwner)",
        "expressionValues" : {
            ":expectedOwner" : $util.dynamodb.toDynamoDBJson($context.identity.username)
        }
    }
}
```

### 사용 사례: 그룹에 새 레코드 생성 허용
<a name="use-case-group-can-create-new-record"></a>

```
#set($expression = "")
#set($expressionValues = {})
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #set( $expression = "${expression} contains(groupsCanAccess, :var$foreach.count )" )
    #set( $val = {})
    #set( $test = $val.put("S", $group))
    #set( $values = $expressionValues.put(":var$foreach.count", $val))
    #if ( $foreach.hasNext )
    #set( $expression = "${expression} OR" )
    #end
#end
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        ## If your table's hash key is not named 'id', update it here. **
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
        ## If your table has a sort key, add it as an item here. **
    },
    "attributeValues" : {
        ## Add an item for each field you would like to store to Amazon DynamoDB. **
        "title" : $util.dynamodb.toDynamoDBJson($ctx.args.title),
        "content": $util.dynamodb.toDynamoDBJson($ctx.args.content),
        "owner": $util.dynamodb.toDynamoDBJson($context.identity.username)
    },
    "condition" : {
        "expression": $util.toJson("attribute_not_exists(id) AND $expression"),
        "expressionValues": $utils.toJson($expressionValues)
    }
}
```

### 사용 사례: 그룹에 기존 레코드 업데이트 허용
<a name="use-case-group-can-update-existing-record"></a>

```
#set($expression = "")
#set($expressionValues = {})
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #set( $expression = "${expression} contains(groupsCanAccess, :var$foreach.count )" )
    #set( $val = {})
    #set( $test = $val.put("S", $group))
    #set( $values = $expressionValues.put(":var$foreach.count", $val))
    #if ( $foreach.hasNext )
    #set( $expression = "${expression} OR" )
    #end
#end
{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "update":{
                "expression" : "SET title = :title, content = :content",
        "expressionValues": {
            ":title" : $util.dynamodb.toDynamoDBJson($ctx.args.title),
            ":content" : $util.dynamodb.toDynamoDBJson($ctx.args.content)
        }
    },
    "condition" : {
        "expression": $util.toJson($expression),
        "expressionValues": $utils.toJson($expressionValues)
    }
}
```

## 퍼블릭 및 프라이빗 레코드
<a name="public-and-private-records"></a>

또한 조건부 필터를 사용하여 데이터를 프라이빗, 퍼블릭 또는 다른 부울 확인으로 표시하도록 선택할 수도 있습니다. 이렇게 하면 조건 필터를 응답 템플릿 내부에서 권한 부여 필터의 일부로서 결합할 수 있습니다. 이 확인을 사용하는 것은 그룹 멤버십을 제어하지 않고 데이터를 임시로 숨기거나 뷰에서 제거할 수 있는 좋은 방법입니다.

예를 들어 DynamoDB 테이블의 각 항목에 대해 `yes` 또는 `no` 값을 사용하여 `public`이라는 속성을 추가했다고 가정하겠습니다. 다음 응답 템플릿을 `GetItem` 호출에서 사용하면 액세스 권한이 있는 그룹 내 사용자이고(AND) 해당 데이터가 퍼블릭으로 표시되는 경우에 한하여 데이터를 표시할 수 있습니다.

```
#set($permissions = $context.result.GroupsCanAccess)
#set($claimPermissions = $context.identity.claims.get("cognito:groups"))

#foreach($per in $permissions)
    #foreach($cgroups in $claimPermissions)
        #if($cgroups == $per)
            #set($hasPermission = true)
        #end
    #end
#end

#if($hasPermission && $context.result.public == 'yes')
    $utils.toJson($context.result)
#else
    $utils.unauthorized()
#end
```

또한 위의 코드는 OR(`||`) 로직을 사용하여 퍼블릭 레코드인 경우 또는 레코드에 대한 권한이 있는 사람에게만 읽기를 허용할 수도 있습니다.

```
#if($hasPermission || $context.result.public == 'yes')
    $utils.toJson($context.result)
#else
    $utils.unauthorized()
#end
```

일반적으로 표준 연산자인 `==`, `!=`, `&&` 및 `||`는 권한 부여 확인 수행 시 유용합니다.

## 실시간 데이터
<a name="security-real-time-data"></a>

이 설명서의 앞부분에 설명된 동일한 기술을 사용하여 클라이언트가 구독을 만들 때 세분화된 액세스 제어를 GraphQL 구독에 적용할 수 있습니다. 구독 필드에 해석기를 연결할 수 있으며, 이때 데이터 원본에서 데이터를 쿼리하고 요청이나 응답 매핑 템플릿에서 조건부 로직을 수행할 수 있습니다. 또한 데이터 구조가 GraphQL 구독의 반환 유형과 일치하는 한, 구독의 초기 결과 등 추가 데이터를 클라이언트로 반환할 수도 있습니다.

### 사용 사례: 사용자가 특정 대화만 구독 가능
<a name="use-case-user-can-subscribe-to-specific-conversations-only"></a>

GrapHQL 구독과 관련된 실시간 데이터의 일반 사용 사례 중 하나는 메시징 또는 프라이빗 채팅 애플리케이션 빌드입니다. 여러 사용자가 있는 채팅 애플리케이션을 작성하려는 경우 두 사람 이상의 여러 사람 간에 대화가 발생할 수 있습니다. 이러한 대화는 프라이빗이나 퍼블릭 ‘대화방’으로 그룹화될 수 있습니다. 따라서, 자신에게 액세스 권한이 부여된 대화(한 개 이상의 그룹일 수 있음)만 구독하도록 사용자에게 권한을 부여할 수 있습니다. 데모 목적으로 제공되는 아래 샘플은 한 사용자가 프라이빗 메시지를 다른 사용자에게 전송하는 단순 사용 사례를 보여줍니다. 설정에는 두 개의 Amazon DynamoDB 테이블이 있습니다.
+ Messages 테이블: (기본 키)`toUser`, (정렬 키)`id` 
+ Permissions 테이블: (기본 키)`username` 

Messages 테이블은 GraphQL 변형을 통해 전송되는 실제 메시지를 저장합니다. Permissions 테이블은 클라이언트 연결 시 권한 부여를 위해 GraphQL 구독에서 확인됩니다. 아래 예제에서는 다음과 같은 GraphQL 스키마를 사용한다고 가정합니다.

```
input CreateUserPermissionsInput {
    user: String!
    isAuthorizedForSubscriptions: Boolean
}

type Message {
    id: ID
    toUser: String
    fromUser: String
    content: String
}

type MessageConnection {
    items: [Message]
    nextToken: String
}

type Mutation {
    sendMessage(toUser: String!, content: String!): Message
    createUserPermissions(input: CreateUserPermissionsInput!): UserPermissions
    updateUserPermissions(input: UpdateUserPermissionInput!): UserPermissions
}

type Query {
    getMyMessages(first: Int, after: String): MessageConnection
    getUserPermissions(user: String!): UserPermissions
}

type Subscription {
    newMessage(toUser: String!): Message
        @aws_subscribe(mutations: ["sendMessage"])
}

input UpdateUserPermissionInput {
    user: String!
    isAuthorizedForSubscriptions: Boolean
}

type UserPermissions {
    user: String
    isAuthorizedForSubscriptions: Boolean
}

schema {
    query: Query
    mutation: Mutation
    subscription: Subscription
}
```

`createUserPermissions()`와 같은 표준 작업 중 일부는 구독 해석기를 보여주기 위해 아래에 포함되지 않지만, DynamoDB 해석기의 표준 구현입니다. 대신에 해석기를 사용하는 구독 권한 부여 흐름을 중점적으로 살펴보겠습니다. 한 사용자에서 다른 사용자로 메시지를 전송하려면 해석기를 `sendMessage()` 필드에 연결하고 다음과 같은 요청 템플릿과 함께 **Messages** 테이블 데이터 원본을 선택합니다.

```
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "toUser" : $util.dynamodb.toDynamoDBJson($ctx.args.toUser),
        "id" : $util.dynamodb.toDynamoDBJson($util.autoId())
    },
    "attributeValues" : {
        "fromUser" : $util.dynamodb.toDynamoDBJson($context.identity.username),
        "content" : $util.dynamodb.toDynamoDBJson($ctx.args.content),
    }
}
```

이 예제에서는 `$context.identity.username`을 사용합니다. 그러면 AWS Identity and Access Management 또는 Amazon Cognito 사용자의 사용자 정보가 반환됩니다. 응답 템플릿은 `$util.toJson($ctx.result)`의 단순 전달입니다. 저장하고 스키마 페이지로 돌아갑니다. 그런 다음 **권한** 테이블을 데이터 소스로 사용하고 다음 요청 매핑 템플릿을 사용하여 `newMessage()` 구독용 해석기를 연결합니다.

```
{
    "version": "2018-05-29",
    "operation": "GetItem",
    "key": {
        "username": $util.dynamodb.toDynamoDBJson($ctx.identity.username),
    },
}
```

그러고 나면 다음과 같은 응답 매핑 템플릿과 **Permissions** 테이블의 데이터를 사용하여 권한 부여 확인을 수행합니다.

```
#if(! ${context.result})
    $utils.unauthorized()
#elseif(${context.identity.username} != ${context.arguments.toUser})
    $utils.unauthorized()
#elseif(! ${context.result.isAuthorizedForSubscriptions})
    $utils.unauthorized()
#else
##User is authorized, but we return null to continue
    null
#end
```

여기서는 세 가지 권한 부여 확인을 수행하려고 합니다. 첫 번째는 결과가 반환되는지 확인합니다. 두 번째는 사용자가 다른 사람에게 해당되는 메시지를 구독하고 있지 않은지 확인합니다. 세 번째는 `BOOL`로 저장된 `isAuthorizedForSubscriptions`의 DynamoDB 속성을 확인하여 사용자가 모든 필드를 구독하도록 허용되었는지 확인합니다.

테스트하려면 Amazon Cognito 사용자 풀과 “Nadia”라는 사용자를 사용하여 AWS AppSync 콘솔에 로그인한 다음 다음 GraphQL 구독을 실행합니다.

```
subscription AuthorizedSubscription {
    newMessage(toUser: "Nadia") {
        id
        toUser
        fromUser
        content
    }
}
```

**Permissions** 테이블에서 `isAuthorizedForSubscriptions`가 `true`로 설정된 `Nadia`의 키 속성 `username`에 대한 레코드가 있는 경우 성공적인 응답이 표시됩니다. 위의 `username` 쿼리에서 다른 `newMessage()`을 시도하면 오류가 반환됩니다.

# AWS WAF 를 사용하여 AWS AppSync APIs 보호
<a name="WAF-Integration"></a>

AWS WAF 는 웹 애플리케이션과 APIs으로부터 보호하는 데 도움이 되는 웹 애플리케이션 방화벽입니다. WAF를 통해 사용자가 정의한 맞춤형 웹 보안 규칙 및 조건에 따라 웹 요청을 허용, 차단 또는 모니터링하는 규칙 집합(이른바 웹 액세스 제어 목록(웹 ACL)이라고 함)을 구성할 수 있습니다. AWS AppSync API를와 통합 AWS WAF하면 API에서 허용하는 HTTP 트래픽에 대한 제어 및 가시성을 높일 수 있습니다. 자세한 내용은 AWS WAF 개발자 안내서의 [AWS WAF 작동 방식을](https://docs.aws.amazon.com/waf/latest/developerguide/how-aws-waf-works.html) AWS WAF참조하세요.

 AWS WAF 를 사용하여 SQL 삽입 및 교차 사이트 스크립팅(XSS) 공격과 같은 일반적인 웹 악용으로부터 AppSync API를 보호할 수 있습니다. 이는 API 가용성 및 성능에 영향을 미치거나, 보안을 손상시키거나, 리소스를 과도하게 소비할 수 있습니다. 예를 들어 지정된 IP 주소 범위의 요청, CIDR 블록의 요청, 특정 국가 또는 리전에서 시작된 요청, 악성 SQL 코드가 포함된 요청, 악성 스크립트가 포함된 요청을 허용하거나 차단하는 규칙을 만들 수 있습니다.

HTTP 헤더, 메서드, 쿼리 문자열, URI 및 요청 본문(처음 8KB로 제한)에 지정된 문자열이나 정규식 패턴과 일치하는 규칙을 만들 수도 있습니다. 또한 특정 사용자 에이전트, 악성 봇, 콘텐츠 스크래퍼의 공격을 차단하는 규칙을 생성할 수 있습니다. 예를 들어, 비율 기반 규칙을 사용하여 연속적으로 업데이트되는 이후 5분 동안 각 클라이언트 IP에서 허용하는 웹 요청 수를 지정할 수 있습니다.

지원되는 규칙 유형과 추가 AWS WAF 기능에 대한 자세한 내용은 [AWS WAF 개발자 안내서](https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html) 및 [AWS WAF API 참조](https://docs.aws.amazon.com/waf/latest/APIReference/API_Types_AWS_WAFV2.html)를 참조하세요.

**중요**  
AWS WAF 는 웹 악용에 대한 첫 번째 방어선입니다. API에서 AWS WAF 를 활성화하면 AWS WAF API 키 권한 부여, IAM 정책, OIDC 토큰 및 Amazon Cognito 사용자 풀과 같은 다른 액세스 제어 기능보다 먼저 규칙이 평가됩니다.

## AppSync API를와 통합 AWS WAF
<a name="integrate-API-with-WAF"></a>

 AWS CLI AWS CloudFormation, 또는 기타 호환되는 클라이언트를 AWS WAF 사용하여 Appsync API AWS Management Console를와 통합할 수 있습니다.

**AWS AppSync API를와 통합하려면 AWS WAF**

1.  AWS WAF 웹 ACL을 생성합니다. [AWS WAF 콘솔](https://console.aws.amazon.com/waf/) 사용의 자세한 단계는 [웹 ACL 생성](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-creating.html)을 참조하세요.

1. 웹 ACL의 규칙을 정의합니다. 규칙은 웹 ACL을 생성하는 과정에서 정의됩니다. 규칙 구성 방법에 대한 자세한 내용은 [AWS WAF 규칙](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rules.html)을 참조하세요. AWS AppSync API에 대해 정의할 수 있는 유용한 규칙의 예는 섹션을 참조하세요[웹 ACL에 대한 규칙 생성](#Creating-web-acl-rules).

1. 웹 ACL을 AWS AppSync API와 연결합니다. [AWS WAF 콘솔](https://console.aws.amazon.com/wafv2/) 또는 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)에서 이 단계를 수행할 수 있습니다.
   + 웹 ACL을 AWS WAF 콘솔의 AWS AppSync API와 연결하려면 AWS WAF 개발자 안내서의 [웹 ACL을 리소스와 AWS 연결 또는 연결 해제](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-associating-aws-resource.html) 지침을 따르세요.
   + 콘솔에서 웹 ACL을 AWS AppSync API AWS AppSync 와 연결하려면

     1. 에 로그인 AWS Management Console 하고 [AppSync 콘솔](https://console.aws.amazon.com/appsync/)을 엽니다.

     1. 웹 ACL과 연결할 API를 선택합니다.

     1. 탐색 창에서 **설정**을 선택합니다.

     1. **웹 애플리케이션 방화벽** 섹션에서 ** AWS WAF활성화**를 켭니다.

     1. **웹 ACL** 드롭다운 목록에서 API와 연결할 웹 ACL의 이름을 선택합니다.

     1. **저장**을 선택하여 웹 ACL을 API와 연결합니다.

   

**참고**  
 AWS WAF 콘솔에서 웹 ACL을 생성한 후 새 웹 ACL을 사용할 수 있는 데 몇 분 정도 걸릴 수 있습니다. **웹 애플리케이션 방화벽** 메뉴에 새로 만든 웹 ACL이 표시되지 않는 경우, 몇 분 정도 기다린 후 단계를 다시 시도하여 웹 ACL을 API와 연결해 봅니다.

**참고**  
AWS WAF 통합은 실시간 엔드포인트에 대한 `Subscription registration message` 이벤트만 지원합니다. AWS AppSync 는 `Subscription registration message` 차단된에 대한 메시지 대신 오류 `start_ack` 메시지로 응답합니다 AWS WAF.

웹 ACL을 AWS AppSync API와 연결한 후 AWS WAF APIs를 사용하여 웹 ACL을 관리합니다. AWS AppSync API를 다른 웹 ACL과 연결하려는 경우가 아니면 웹 ACL을 AWS AppSync API와 다시 연결할 필요가 없습니다.

## 웹 ACL에 대한 규칙 생성
<a name="Creating-web-acl-rules"></a>

규칙은 웹 요청을 검사하는 방법과 웹 요청이 검사 기준과 일치할 때 수행할 작업을 정의합니다. 규칙은 자체 AWS WAF 적으로에 존재하지 않습니다. 규칙 그룹 또는 규칙이 정의된 웹 ACL에서 이름으로 규칙에 액세스할 수 있습니다. 자세한 내용은 [AWS WAF 규칙](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rules.html)을 참조하세요. 다음 예제는 AppSync API를 보호하는 데 유용한 규칙을 정의하고 연결하는 방법을 보여줍니다.

**Example 요청 본문 크기를 제한하는 웹 ACL 규칙**  
다음은 요청의 본문 크기를 제한하는 규칙의 예입니다. AWS WAF 콘솔에서 웹 ACL을 생성할 때 **규칙 JSON 편집기**에 입력됩니다.  

```
{
    "Name": "BodySizeRule", 
    "Priority": 1, 
    "Action": {
        "Block": {}
    }, 
    "Statement": {
        "SizeConstraintStatement": {
            "ComparisonOperator": "GE",
            "FieldToMatch": {
                "Body": {}
            },
            "Size": 1024, 
            "TextTransformations": [
                {
                    "Priority": 0, 
                    "Type": "NONE"
                }
             ]
          }
       }, 
       "VisibilityConfig": {
           "CloudWatchMetricsEnabled": true, 
           "MetricName": "BodySizeRule", 
           "SampledRequestsEnabled": true
        }
}
```
앞의 예제 규칙을 사용하여 웹 ACL을 생성한 후에는 이를 AppSync API와 연결해야 합니다. 를 사용하는 대신 다음 명령을 실행 AWS CLI 하여에서이 단계를 수행할 AWS Management Console수 있습니다.  

```
aws waf associate-web-acl --web-acl-id waf-web-acl-arn --resource-arn appsync-api-arn
```
변경 사항이 전파되는 데 몇 분 정도 걸릴 수 있지만, 이 명령을 실행한 후에는 1024바이트보다 큰 본문이 포함된 요청이 AWS AppSync에 의해 거부됩니다.  
 AWS WAF 콘솔에서 새 웹 ACL을 생성한 후 웹 ACL을 API와 연결하는 데 몇 분 정도 걸릴 수 있습니다. CLI 명령을 실행할 때 `WAFUnavailableEntityException` 오류가 발생하면 몇 분 정도 기다렸다가 명령을 다시 실행해 보세요.

**Example 단일 IP 주소에서 요청을 제한하는 웹 ACL 규칙**  
다음은 AppSync API를 단일 IP 주소에서 요청 100개로 제한하는 규칙의 예입니다. 이는 AWS WAF 콘솔에서 속도 기반 규칙을 사용하여 웹 ACL을 생성할 때 규칙 **JSON 편집기**에 입력됩니다.  

```
{
  "Name": "Throttle",
  "Priority": 0,
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "Throttle"
  },
  "Statement": {
    "RateBasedStatement": {
      "Limit": 100,
      "AggregateKeyType": "IP"
    }
  }
}
```
앞의 예제 규칙을 사용하여 웹 ACL을 생성한 후에는 이를 AppSync API와 연결해야 합니다. 다음 명령을 실행 AWS CLI 하여에서이 단계를 수행할 수 있습니다.  

```
aws waf associate-web-acl --web-acl-id waf-web-acl-arn --resource-arn appsync-api-arn
```

**Example API에 대한 GraphQL \$1\$1\$1\$1schema 내부 검사 쿼리를 방지하는 웹 ACL 규칙**  
다음은 API에 대한 GraphQL \$1\$1schema 내부 검사 쿼리를 방지하는 규칙의 예입니다. 문자열 '\$1\$1schema'를 포함하는 모든 HTTP 본문은 차단됩니다. AWS WAF 콘솔에서 웹 ACL을 생성할 때 **규칙 JSON 편집기**에 입력됩니다.  

```
{
  "Name": "BodyRule",
  "Priority": 5,
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "BodyRule"
  },
  "Statement": {
    "ByteMatchStatement": {
      "FieldToMatch": {
        "Body": {}
      },
      "PositionalConstraint": "CONTAINS",
      "SearchString": "__schema",
      "TextTransformations": [
        {
          "Type": "NONE",
          "Priority": 0
        }
      ]
    }
  }
}
```
앞의 예제 규칙을 사용하여 웹 ACL을 생성한 후에는 이를 AppSync API와 연결해야 합니다. 다음 명령을 실행 AWS CLI 하여에서이 단계를 수행할 수 있습니다.  

```
aws waf associate-web-acl --web-acl-id waf-web-acl-arn --resource-arn appsync-api-arn
```