web-dev-qa-db-fra.com

Pourquoi recevrais-je un message interdit de AWS API Gateway, même si les choses fonctionnent en interne?

J'ai configuré la passerelle AWS API pour un point de terminaison public sans authentification. Il se connecte à une websocket qui déclenche une Lambda.

Je créais des connexions avec Python websocket-client lib at https://pypi.org/project/websocket_client/ .

J'ai remarqué que les connexions échouaient ~ 10% du temps et s'aggravaient à mesure que j'augmentais la charge. Je ne trouve aucun endroit qui pourrait m'étouffer, car mes paramètres généraux de la passerelle API disent Your current account level throttling rate is 10000 requests per second with a burst of 5000 requests.. C'est à côté du point que seulement 2-3 demandes par seconde déclencheraient un problème assez souvent.

Pendant ce temps, la réponse d'échec serait comme {u'message': u'Forbidden', u'connectionId': u'Z2Jp-dR5vHcCJkg=', u'requestId': u'Z2JqAEJRvHcFzvg='}

Je suis allé dans mes informations de journal CloudWatch et j'ai recherché l'ID de connexion et l'ID de demande. Le groupe de journaux de la passerelle API ne trouverait aucun résultat avec l'un ou l'autre ID. Pourtant, une recherche sur ma Lambda qui se déclenche sur la connexion Websocket, aurait un journal avec cet ID de connexion. Le journal montrait que tout fonctionnait comme prévu de notre côté. Le lambda exécute simplement une requête MySQL qui se déclenche.

Pourquoi devrais-je obtenir une réponse d'interdit, malgré le fonctionnement lambda comme prévu?

La question existante sur obtenir un message: réponse interdite de la passerelle AWS API , semble répondre si elle retourne TOUJOURS interdite pour certains points de terminaison privés. Rien ne correspondait à mon cas d'utilisation.

[~ # ~] mise à jour [~ # ~]

Je pense que cela peut être lié à locust.io, ou python, que j'utilise pour me connecter à chaque seconde. J'ai installé https://www.npmjs.com/package/wscat sur ma machine et je me connecte et ferme le plus rapidement possible à plusieurs reprises. Je ne reçois pas de message Forbidden. C'est juste déroutant car je ne sais pas comment la façon dont je me connecte cracherait au hasard un Forbidden message parfois.

class SocketClient(object):
    def __init__(self, Host):
        self.Host = Host
        self.session_id = uuid4().hex

    def connect(self):
        self.ws = websocket.WebSocket()
        self.ws.settimeout(10)
        self.ws.connect(self.Host)

        events.quitting += self.on_close

        data = self.attach_session({})
        return data

    def attach_session(self, payload):
        message_id = uuid4().hex
        start_time = time.time()
        e = None
        try:
            print("Sending payload {}".format(payload))
            data = self.send_with_response(payload)
            assert data['mykey']

        except AssertionError as exp:
            e = exp
        except Exception as exp:
            e = exp
            self.ws.close()
            self.connect()
        elapsed = int((time.time() - start_time) * 1000)
        if e:
            events.request_failure.fire(request_type='sockjs', name='send',
                                        response_time=elapsed, exception=e)
        else:
            events.request_success.fire(request_type='sockjs', name='send',
                                        response_time=elapsed,
                                        response_length=0)
        return data

    def send_with_response(self, payload):
        json_data = json.dumps(payload)

        g = gevent.spawn(self.ws.send, json_data)
        g.get(block=True, timeout=2)
        g = gevent.spawn(self.ws.recv)
        result = g.get(block=True, timeout=10)

        json_data = json.loads(result)
        return json_data
    def on_close(self):
        self.ws.close()

class ActionsTaskSet(TaskSet):
    @task
    def streams(self):
        response = self.client.connect()
        logger.info("Connect Response: {}".format(response))

class WSUser(Locust):
    task_set = ActionsTaskSet
    min_wait = 1000
    max_wait = 3000

    def __init__(self, *args, **kwargs):
        super(WSUser, self).__init__(*args, **kwargs)
        self.client = SocketClient('wss://mydomain.amazonaws.com/endpoint')

enter image description here

Mise à jour 2

J'ai activé les journaux d'accès, le seul type de journal qui n'existait pas auparavant. Je peux maintenant voir que mes lambdas obtiennent toujours un 200 sans problème. Le 403 provient d'un MESSAGEeventType qui n'atteint pas un routeKey réel. Je ne sais pas d'où cela vient, mais je suis sûr que trouver cette réponse résoudra le problème.

J'ai également pu confirmer qu'il n'y avait pas de problème ENI.

enter image description here

14
Dave Stein

La charge utile dans mon exemple est vide. L'API est configurée pour utiliser $request.body.action pour connaître la routeKey. La connexion définit la valeur par défaut $connect travaux routiers.

L'ajout d'un action approprié dans mon corps a fait disparaître les 403. Voilà la solution. J'obtenais essentiellement 200 réponses de l'acte de connexion et de déconnexion, mais j'obtenais le 403 chaque fois que mon message sans charge utile passait.

0
Dave Stein

Vous pourriez rencontrer certaines limites liées au VPC. Voir https://winterwindsoftware.com/scaling-lambdas-inside-vpc/ . On dirait que vous pourriez manquer d'ENI. Vous pouvez essayer de déplacer la fonction vers un autre VPC. Combien de temps dure chaque invocation du lambda? Et dans quelle langue êtes-vous lambda écrit?

4
complex