Mam API / Service, że definiuję się z tabelą DYNAMODB. Mam kilka indeksów (zdefiniowanych jako globalny indeks wtórny), aby wspierać kilka pytań. Mam stół zaprojektowany z definicjami GSI i co wygląda jak poprawne zapytania. Jednak otrzymuję ten wyjątek podczas wykonywania zapytania:

{ AccessDeniedException: User: arn:aws:sts::OBSCURED:assumed-role/chatroom-application-dev-us-east-1-lambdaRole/chatroom-application-dev-getRoomMessages is not authorized to perform: dynamodb:Query on resource: arn:aws:dynamodb:us-east-1:OBSCURED:table/messages-table-dev/index/roomIndex
at Request.extractError (/var/task/node_modules/aws-sdk/lib/protocol/json.js:48:27)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:685:12)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
message: 'User: arn:aws:sts::OBSCURED:assumed-role/chatroom-application-dev-us-east-1-lambdaRole/chatroom-application-dev-getRoomMessages is not authorized to perform: dynamodb:Query on resource: arn:aws:dynamodb:us-east-1:OBSCURED:table/messages-table-dev/index/roomIndex',
code: 'AccessDeniedException',
time: 2018-06-02T22:05:46.110Z,
requestId: 'OBSCURED',
statusCode: 400,
retryable: false,
retryDelay: 30.704899664776054 }

Na szczycie wyjątku mówi Arn dla moich metody Getroommesses is not authorized to perform: dynamodb:Query on resource: i pokazuje Arn dla globalnego indeksu wtórnego.

Wydaje się jasne, muszę zdefiniować politykę przyznawania praw do uzyskania dostępu do globalnego indeksu wtórnego. Ale to nie jest jasne, jak. Widziałem inne pytania o stackoverflow o Dynamodb narzekać na rozdrobnioną dokumentację i jak trudno jest znaleźć coś. Muszę się zgodzić. Słowo "rozdrobnione" wprowadza go zbyt lekko.

Używam bezpodstawnych ram. Sekcja provider pokazuje tę politykę / definicję roli:

provider:
  name: aws
  runtime: nodejs8.10
  stage: dev
  region: us-east-1
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource:
        - { "Fn::GetAtt": ["MessagesDynamoDBTable", "Arn" ] }
        - { "Fn::GetAtt": ["#roomIndex", "Arn" ] }
        - { "Fn::GetAtt": ["#userIndex", "Arn" ] }
  environment:
    MESSAGES_TABLE: ${self:custom.tableName}

W sekcji Resource uważam, że mam wymienić zasoby, dla których zadeklarowane są uprawnienia. Pierwsze odniesienia do stołu jako całość. Ostatnie dwa właśnie dodałem i odwołuję się do indeksów.

Edytuj: Po uruchomieniu serverless deploy Drukowano następujący komunikat:

The CloudFormation template is invalid: Template error: instance of Fn::GetAtt references undefined resource #roomIndex

Próbowałem na tym kilku odmian, aby uzyskać ten sam błąd. Co się sprowadza, jest - , jak mam, w serverless.yml, używając składni Cloudfront, zdobądź Arn dla indeksów . Arn istnieje, ponieważ jest pokazany w wyjątku.

Definicja tabeli DYNAMODB:

resources:
  Resources:
    MessagesDynamoDBTable:
      Type: AWS::DynamoDB::Table
      Properties:
        AttributeDefinitions:
          - AttributeName: messageId
            AttributeType: S
          - AttributeName: room
            AttributeType: S
          - AttributeName: userId
            AttributeType: S
        KeySchema:
          - AttributeName: messageId
            KeyType: HASH
        GlobalSecondaryIndexes:
          - IndexName: roomIndex
            KeySchema:
              - AttributeName: room
                KeyType: HASH
            Projection:
              ProjectionType: ALL
            ProvisionedThroughput:
              ReadCapacityUnits: 1
              WriteCapacityUnits: 1
          - IndexName: userIndex
            KeySchema:
              - AttributeName: userId
                KeyType: HASH
            Projection:
              ProjectionType: ALL
            ProvisionedThroughput:
              ReadCapacityUnits: 1
              WriteCapacityUnits: 1
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:custom.tableName}

Zapytanie używane odpowiadające powyższym wyjątku:

{
    "TableName": "messages-table-dev",
    "IndexName": "roomIndex",
    "KeyConditionExpression": "#roomIndex = :room",
    "ExpressionAttributeNames": {
        "#roomIndex": "room"
    },
    "ExpressionAttributeValues": {
        ":room": {
            "S": "everyone"
        }
    }
}

I fragment kodu funkcji LAMBDA, który generuje zapytanie:

app.get('/messages/room/:room', (req, res) => {
    const params = {
        TableName: MESSAGES_TABLE,
        IndexName: "roomIndex",
        KeyConditionExpression: '#roomIndex = :room',
        ExpressionAttributeNames: { '#roomIndex': 'room' },
        ExpressionAttributeValues: {
            ":room": { S: `${req.params.room}` }
        },
    };
    console.log(`QUERY ROOM ${JSON.stringify(params)}`);
    dynamoDb.query(params, (error, result) => {
        if (error) {
            console.log(error);
            res.status(400).json({ error: 'Could not get messages' });
        } else {
            res.json(result.Items);
        }
    });
});
4
David Herron 3 czerwiec 2018, 01:43

3 odpowiedzi

Najlepsza odpowiedź

Znalazłem lepszą odpowiedź niż została wysłana przez Jake.lang. Edytuj: Nie widziałem jego drugiego komentarza, w którym zasugerował następujące.

Jak zauważył, jego był nieprawidłowy, ponieważ Arn może zmienić z poprawnych powodów. Jednak rozwiązanie powstało, ponieważ Arn dla globalnego indeksu wtórnego jest dołączenie "/ indexName" do Arn do tabeli. Oznacza to, że instrukcja polityczna może być:

iamRoleStatements:
  - Effect: Allow
    Action:
      - dynamodb:Query
      - dynamodb:Scan
      - dynamodb:GetItem
      - dynamodb:PutItem
      - dynamodb:UpdateItem
      - dynamodb:DeleteItem
    Resource:
      - { "Fn::GetAtt": ["MessagesDynamoDBTable", "Arn" ] }
      - { "Fn::Join": [ "/", [ 
          { "Fn::GetAtt": ["MessagesDynamoDBTable", "Arn" ] }, "index", "roomIndex" 
        ]]}
      - { "Fn::Join": [ "/", [
          { "Fn::GetAtt": ["MessagesDynamoDBTable", "Arn" ] }, "index", "userIndex" 
        ]]}

"FN :: Dołącz" bit pochodzi z cloudformation i jest operacją "dołącz". Potrzeba tablicy ciągów, połączając ich za pomocą pierwszego argumentu. Dlatego jest to raczej zawiła i zbyt skomplikowana metoda obliczania wymaganego Arn w niniejszym oświadczeniu o polityce.

Do dokumentacji, zobacz: HTTPS: // Docs. AWS.Amazon.com/awsCloudformation/latest/Usuweride/intrinsic-Function-Reference-join.html.

8
David Herron 5 czerwiec 2018, 05:46

Zamiast Fn::Join możesz użyć !Sub "${MessagesDynamoDBTable.Arn}", jest prostsze. Co więcej, jeśli chcesz uzyskać dostęp do wszystkich indeksów (zwykle mój przypadek), to /index/* to wszystko, czego potrzebujesz.

Przykład:

...
      Policies:
        - Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - dynamodb:Query
              Resource:
                - !Sub "${MessagesDynamoDBTable.Arn}"
                - !Sub "${MessagesDynamoDBTable.Arn}/index/*"
...
2
Stan Prokop 17 maj 2019, 07:29

Oto jak zadeklarowałem moje uprawnienia GSI w Servelless. Nie jestem pewien, ale może problem jest potrzebny, aby zadeklarować działania dla każdego zasobu niezależnie?

iamRoleStatements: 
  - Effect: Allow
    Action:
      - dynamodb:Query
      - dynamodb:GetItem
      - dynamodb:PutItem
    Resource: "arn:REDACTED:table/TABLENAME”
  - Effect: Allow
    Action:
      - dynamodb:Query
    Resource: "arn:REDACTED:table/TABLENAME/index/INDEXNAME”

To hardcoding ARN prawdopodobnie nie jest najlepszą rzeczą, ale działa dobrze dla mojego rozwoju.

1
jake.lange 2 czerwiec 2018, 23:04