AWS SQS - 一致的“对资源X的访问被拒绝”

时间:2016-06-30 19:11:44

标签: php amazon-web-services amazon-sqs

好吧,我现在已经知道了,真的需要另一双眼睛。

我正在尝试创建一个非常轻量级的PHP端点,将数据推送到SQS队列以进行离线处理。如果我能提供帮助,我不想利用整个AWS SDK。

IAM Side

  • 我创建了一个Group并为其分配了AmazonSQSFullAccess Policy
  • 我创建了一个用户并将其分配给上述组
  • 我下载了凭据。此时我已经验证了十几次

SQS Side

  • 创建了SQS队列
  • 允许通过队列上的权限小部件访问所有人(考虑到IAM,但我知道的内容似乎是多余的)。使用下面的代码推送消息,它可以正常工作 -
  • 通过“权限”小组件限制对IAM中定义的单个用户的访问。获取“访问资源$ sqs_endpoint denied”,其中$ sqs_endpoint =我的端点

好的,所以我认为它必须是签名。我下载AWSv4 Test Suite并将其抛在调试开关后面。我收到了有效的回复。但是,当我关闭调试时 - 返回错误信息。

我已经尝试过base64编码有效负载,以防这是一个奇怪的转义问题,但仍然没有(当我允许访问所有人时,我能够推送数据)。

无论如何,这是我的代码。它必须是IAM许可问题,不是吗?我似乎无法摆动圆圈:

<?php  
    define( 'DEBUG', false );
    define( 'AMZN_ALGO', 'AWS4-HMAC-SHA256' );
    define( 'HASH_ALGO', 'SHA256' );


    function getSignatureKey( $key, $date, $region, $service ) {
        $kDate = hash_hmac( HASH_ALGO, $date, 'AWS4' . $key, true );
        $kRegion = hash_hmac( HASH_ALGO, $region, $kDate, true );
        $kService = hash_hmac( HASH_ALGO, $service, $kRegion, true );
        $kSigning = hash_hmac( HASH_ALGO, 'aws4_request', $kService, true );
        return $kSigning;
    }

    // these values are the hashes provided in the test suite to validate your approach
    function compareTestSig( $type, $val ) {
        $testSigs = [
            'sts'=>'2e1cf7ed91881a30569e46552437e4156c823447bf1781b921b5d486c568dd1c',
            'creq'=>'9095672bbd1f56dfc5b65f3e153adc8731a4a654192329106275f4c7b24d0b6e',
            'authz'=>'1a72ec8f64bd914b0e42e42607c7fbce7fb2c7465f63e3092b3b0d39fa77a6fe'  
        ];

        if( $testSigs[$type] === $val ) {
            return true;
        }

        return false;
    }



    $headers = getallheaders();

    /**
      * Config
      * DEBUG = true are all the values from the AWS 4 Test Suite
      */    
    if( DEBUG === true ) {
        define( 'ACCESS_KEY', 'AKIDEXAMPLE' );
        define( 'SECRET_ACCESS_KEY', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' );
        define( 'ENDPOINT', 'https://example.amazonaws.com/' );

        $amznDate = '20150830T123600Z';
        $nrmlDate = '20150830';
        $service = 'service';
        $version = '2012-11-05';

        $payload = 'Param1=value1';                  
    } else {
        define( 'ACCESS_KEY', 'MY_ACCESS_KEY_I_KNOW_IS_CORRECT' );
        define( 'SECRET_ACCESS_KEY', 'MY_SECRET_ACCESS_KEY_I_CHECKED_100_TIMES' );
        define( 'ENDPOINT', 'https://sqs.us-east-1.amazonaws.com/[ENDPOINT_ID]/[QUEUE_NAME]' );

        $amznDate = gmdate( "Ymd\THis\Z" );
        $nrmlDate = gmdate( 'Ymd' );
        $service = 'sqs';
        $version = '2012-11-05';

        // create the payload
        $pBody = [];
        $pBody['Action'] = 'SendMessage';
        $pBody['MessageBody'] = json_encode( $headers );
        $pBody['Version'] = $version;
        $payload = http_build_query( $pBody);
    }

    $host = parse_url( ENDPOINT, PHP_URL_HOST );
    $path = parse_url( ENDPOINT, PHP_URL_PATH );  
    $region = 'us-east-1';
    $contentType = 'application/x-www-form-urlencoded; charset=utf8';
    $scope = sprintf( '%s/%s/%s/%s', $nrmlDate, $region, $service, 'aws4_request' );

    $payloadHash = hash( HASH_ALGO, $payload );

    if( DEBUG ) {
        if( compareTestSig( 'creq', $payloadHash ) ) {
            var_dump( 'CREQ sig PASS' );
        } else {
            var_dump( 'CREQ sig NO PASS' );
            exit;
        }
    }

    /**
      * Sign, seal, deliver.
      * First, create the header string
      */
    $aggregate = [
        'content-type' => $contentType,
        'host' => $host,
        'x-amz-date' => $amznDate
    ];

    ksort( $aggregate );
    $canonHeaders = [];
    foreach( $aggregate as $k=>$v ) {
        $canonHeaders[] = sprintf( "%s:%s", $k, $v );
    }
    $signedHeadersString = implode( ';', array_keys( $aggregate ) );

    /**
      * next, create the canonical request and hash it
      */
    $canon = sprintf( "%s\n%s\n%s\n%s\n\n%s\n%s", 
        'POST', 
        $path,
        '',
        implode( "\n", $canonHeaders ),
        $signedHeadersString,
        $payloadHash
    );

    $canonHash = hash( HASH_ALGO, $canon );
    if( DEBUG ) {
        if( compareTestSig( 'sts', $canonHash ) ) {
            var_dump( 'STS sig PASS' );
        } else {
            var_dump( 'STS sig NO PASS' );
            exit;
        }
    }

    $toSign = sprintf( "%s\n%s\n%s\n%s", AMZN_ALGO, $amznDate, $scope, $canonHash );

    // signingKey will be bin, signature will be in hex
    $signingKey = getSignatureKey( SECRET_ACCESS_KEY, $nrmlDate, $region, $service );
    $signature = hash_hmac( HASH_ALGO, $toSign, $signingKey );

    if( DEBUG ) {
        if( compareTestSig( 'authz', $signature ) ) {
            var_dump( 'AUTHZ sig PASS' );
        } else {
            var_dump( 'AUTHZ sig NOPASS' );
            exit;
        }
    }

    /**
    * set up the post headers
    **/
    $postHeaders = [];
    $postHeaders['Content-Type'] = $contentType;    
    $postHeaders['Host'] = $host;
    $postHeaders['X-Amz-Date'] = $amznDate;
    $postHeaders['Authorization'] = sprintf( "%s Credential=%s, SignedHeaders=%s, Signature=%s", 
        AMZN_ALGO,
        ACCESS_KEY . '/' . $scope,
        $signedHeadersString,
        $signature
    );

    //do it
    $ch = curl_init();
    curl_setopt( $ch, CURLOPT_URL, ENDPOINT );
    curl_setopt( $ch, CURLOPT_POST, 1 );
    curl_setopt( $ch, CURLOPT_HTTPHEADER, $postHeaders );
    curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    $output = curl_exec( $ch );
    curl_close( $ch );

    $xml = simplexml_load_string( $output );

    if( empty( $xml ) ) {
        var_dump( $output );
        die( 'UnknownOperationException' );
    }

    if(! empty( $xml->Error ) ) {
        printf( "ERROR %s : %s", $xml->Error->Code, $xml->Error->Message );
        exit;
    }


    echo 'OK=1;';
    exit;
?>

0 个答案:

没有答案