Aws-cdk: appsync apikey missing dependency on schema?

Created on 23 May 2020  ยท  6Comments  ยท  Source: aws/aws-cdk

I hit ConcurrentModificationExceptions consistently if I don't manually insert a dependency between each Resolver and the schema of its appsync API. (Note that the dependency between the resolver and the API itself is ok.)

Reproduction Steps

Create any appsync schema with multiple dynamo resolvers (though probably any type will have the same problem).

Error Log

ConcurrentModification exceptions, followed by rollback, unless you manually add every dependency by hand

Environment

  • CLI Version : 1.39
  • Framework Version:
  • *OS : macos *
  • Language : python

Other


This is :bug: Bug Report

@aws-cdaws-appsync bug in-progress p1

Most helpful comment

@fulghum I found a way to make your own api key through the L1 constructs.

Thankfully, the CfnGraphQLSchema is exposed by the GraphQL Api ๐Ÿ˜€ so the work just becomes creating an Api Key that is attached to the GraphQL API.

@serverlessunicorn I hope this workaround helps!

In order to do this and prevent big headache I'm going to list two scenarios:

  1. If you want Api Key to be the default authentication type:

    Default Authentication Workaround

    If you want your API to default to Api Key authentication, first set the AuthorizationType to IAM because it requires no configuration.

    python api = appsync.GraphQLApi(self, 'api', name='demo', schema_definition_file=os.path.join(os.getcwd(), "schema.graphql"), authorization_config=appsync.AuthorizationConfig( default_authorization=appsync.AuthorizationMode( authorization_type=appsync.AuthorizationType.IAM ), ) )
    Next, override the CloudFormation property AuthenticationType from AWS_IAM to API_KEY

    ```python
    # Expose CfnResource
    cfn_api = api.node.default_child

    # Override its property to have default AuthenticationType to be ApiKey
    cfn_api.add_property_override("AuthenticationType", "API_KEY")
    ```

    Finally, create the CfnApiKey for your GraphQL API
    ```python
    # Create Api Key
    api_key = appsync.CfnApiKey(self, 'ApiKey', api_id=api.api_id)

    # Add Dependency to Schema
    api_key.add_depends_on(api.schema)
    ```

  2. If you want Api Key to be an additional Authentication Mode:

    Additional Authentication Workaround

    Given any GraphQL Api configuration (as long as you don't specify containing configuration for ApiKey)

    Override the CloudFormation property AdditionalAuthenticationProviders to include API_KEY.

    ```python
    # Expose CfnResource
    cfn_api = api.node.default_child

    # Override Property to add API_KEY
    # (if you have other additional providers, you will have to add them here as well)
    cfn_api.add_property_override("AdditionalAuthenticationProviders", [
    { "AuthenticationType": "API_KEY"}
    ])
    ```

    Finally, create the CfnApiKey for your GraphQL API

    ```python
    # Create Api Key
    api_key = appsync.CfnApiKey(self, 'ApiKey', api_id=api.api_id)

    # Add Dependency to Schema
    api_key.add_depends_on(api.schema)
    ```

To learn more about Escape Hatches, see these docs

The most important part of all of this is to override the CloudFormation Property, such that AppSync recognizes that Api Key is a legal authentication type: without it, the Api Key will not work.

All 6 comments

Oooh this makes sense. Just to clarify, when you say manually add dependency you mean with Construct.addDependency right?

Yup.

On Tue, May 26, 2020 at 5:07 PM Mitchell Valine notifications@github.com
wrote:

Oooh this makes sense. Just to clarify, when you say manually add
dependency you mean with Construct.addDependency right?

โ€”
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/aws/aws-cdk/issues/8168#issuecomment-634344951, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/ANCTK333IP5T7NACGPFNUOLRTRKURANCNFSM4NIH23NQ
.

I was talking with @serverlessunicorn about this issue and it sounds like it's hitting him and his dev team more often lately...

The error coming back is:
CREATE_FAILED for AWS::AppSync::ApiKey | Schema is currently being altered, please wait until that is complete. (Service: AWSAppSync; Status Code: 409; Error Code: ConcurrentModificationException

I see that we already have a dependency declared from the Resolver resource to the API schema resource:
https://github.com/aws/aws-cdk/blob/fbb04183ea77bcf630c39fa22893039865782a12/packages/%40aws-cdk/aws-appsync/lib/resolver.ts#L82

Are we missing a dependency from the API key resource to the API schema resource as well?
https://github.com/aws/aws-cdk/blob/fbb04183ea77bcf630c39fa22893039865782a12/packages/%40aws-cdk/aws-appsync/lib/graphqlapi.ts#L404

Any other ideas?

@serverlessunicorn I've been trying to recreate this bug but to no avail. I'm guessing the issue has a higher likelihood of arising when the GraphQL Schema is bigger?

@fulghum suggested to test by adding a dependency between the Api Key and the Api Schema. Like so

api.apiKey().addDependency(api.schema);

Unfortunately the property apiKey in cdk returns a string not the CfnResource. So there is no easy way I can see to add a dependency between ApiKey and the schema at the moment.

I can add a link between ApiKey and Schema in this PR #9122 and push for it to get merged by the end of next week. If that sounds alright with the two of you?

Thanks @BryanPan342 ๐Ÿ˜„ Is there an easy way to use the Escape Hatch mechanism to pop open the construct and get the direct CfnResource for the key and schema? Sharing a snippet of that code would enable @serverlessunicorn to try out the idea in his code. In particular, that would prevent him from having to dig around for the right node names in the L2 construct library code to access the right resource objects through the escape hatch.

Otherwise... if we are confident that adding an explicit dependency between the Key and the Schema resource objects is safe and correct, then it would be great to get that change in. I'm not super deep on AppSync, so I will defer to you and @MrArnoldPalmer or @shivlaks for the safe thing to do there.

Thanks for helping us close up this gap! ๐Ÿ˜„

@fulghum I found a way to make your own api key through the L1 constructs.

Thankfully, the CfnGraphQLSchema is exposed by the GraphQL Api ๐Ÿ˜€ so the work just becomes creating an Api Key that is attached to the GraphQL API.

@serverlessunicorn I hope this workaround helps!

In order to do this and prevent big headache I'm going to list two scenarios:

  1. If you want Api Key to be the default authentication type:

    Default Authentication Workaround

    If you want your API to default to Api Key authentication, first set the AuthorizationType to IAM because it requires no configuration.

    python api = appsync.GraphQLApi(self, 'api', name='demo', schema_definition_file=os.path.join(os.getcwd(), "schema.graphql"), authorization_config=appsync.AuthorizationConfig( default_authorization=appsync.AuthorizationMode( authorization_type=appsync.AuthorizationType.IAM ), ) )
    Next, override the CloudFormation property AuthenticationType from AWS_IAM to API_KEY

    ```python
    # Expose CfnResource
    cfn_api = api.node.default_child

    # Override its property to have default AuthenticationType to be ApiKey
    cfn_api.add_property_override("AuthenticationType", "API_KEY")
    ```

    Finally, create the CfnApiKey for your GraphQL API
    ```python
    # Create Api Key
    api_key = appsync.CfnApiKey(self, 'ApiKey', api_id=api.api_id)

    # Add Dependency to Schema
    api_key.add_depends_on(api.schema)
    ```

  2. If you want Api Key to be an additional Authentication Mode:

    Additional Authentication Workaround

    Given any GraphQL Api configuration (as long as you don't specify containing configuration for ApiKey)

    Override the CloudFormation property AdditionalAuthenticationProviders to include API_KEY.

    ```python
    # Expose CfnResource
    cfn_api = api.node.default_child

    # Override Property to add API_KEY
    # (if you have other additional providers, you will have to add them here as well)
    cfn_api.add_property_override("AdditionalAuthenticationProviders", [
    { "AuthenticationType": "API_KEY"}
    ])
    ```

    Finally, create the CfnApiKey for your GraphQL API

    ```python
    # Create Api Key
    api_key = appsync.CfnApiKey(self, 'ApiKey', api_id=api.api_id)

    # Add Dependency to Schema
    api_key.add_depends_on(api.schema)
    ```

To learn more about Escape Hatches, see these docs

The most important part of all of this is to override the CloudFormation Property, such that AppSync recognizes that Api Key is a legal authentication type: without it, the Api Key will not work.

Was this page helpful?
0 / 5 - 0 ratings