InvalidAction on IAM

0

I'm trying to perform a GetPolicy request via a v4 signature signing request and getting an "InvalidAction" response. In fact, I get the same InvalidAction response for any other action that I specify for the IAM service. If I use the exact same signing code and switch to the EC2 service, it works fine. What am I missing?

This is the response I get:

Request URL = https://iam.amazonaws.com?Action=GetPolicy&PolicyArn=arn:aws:iam::111111111111:policy/my-policy&Version=2013-10-15
Response code: 400

<ErrorResponse xmlns="http://webservices.amazon.com/AWSFault/2005-15-09">
  <Error>
    <Type>Sender</Type>
    <Code>InvalidAction</Code>
    <Message>Could not find operation GetPolicy for version 2013-10-15</Message>
  </Error>
  <RequestId>5de4035f-e807-11e9-b65b-85bd552fc7ba</RequestId>
</ErrorResponse>

This is the code I'm using (I followed the instructions here: https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html):

import requests
import sys, os, base64, datetime, hashlib, hmac
method = 'GET'
service = 'iam'
host = 'iam.amazonaws.com'
endpoint = 'https://iam.amazonaws.com'
request_parameters = 'Action=GetPolicy&PolicyArn=arn:aws:iam::111111111111:policy/my-policy&Version=2013-10-15'
access_key = 'XXX'
secret_key = 'XXX'
region = 'us-east-1'

def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()

def getSignatureKey(key, dateStamp, regionName, serviceName):
    kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
    kRegion = sign(kDate, regionName)
    kService = sign(kRegion, serviceName)
    kSigning = sign(kService, 'aws4_request')
    return kSigning

t = datetime.datetime.utcnow()
amzdate = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d')
canonical_uri = '/'
canonical_querystring = request_parameters
canonical_headers = 'host:' + host + '\n' + 'x-amz-date:' + amzdate + '\n'
signed_headers = 'host;x-amz-date'
payload_hash = hashlib.sha256(('').encode('utf-8')).hexdigest()
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
string_to_sign = algorithm + '\n' +  amzdate + '\n' +  credential_scope + '\n' +  hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
signing_key = getSignatureKey(secret_key, datestamp, region, service)
signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' +  'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
headers = {'x-amz-date':amzdate, 'Authorization':authorization_header}
request_url = endpoint + '?' + canonical_querystring
print('Request URL = ' + request_url)
r = requests.get(request_url, headers=headers)
print('Response code: %d\n' % r.status_code)

Sorry for the poor formatting. Any help would be greatly appreciated.

tomdaq
asked 5 years ago528 views
4 Answers
0

Hi,
IAM API reference Document for GetPolicy shows the sample request as "Version=2010-05-08".
https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html
I verified that if you change:

From:
  &Version=2013-10-15
To:
  &Version=2010-05-08

It will fix the problem "Could not find operation GetPolicy for version 2013-10-15". After fixing that problem, you will then get the error:

<Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method.
Consult the service documentation for details.</Message>

This is because you need to url encode the Arn of the policy including the slashes. You will need to change your code below, like the following to get it to work:
At the top of the file, add:

import urllib.parse

Then change the following:

From:
request_parameters = 'Action=GetPolicy&PolicyArn=arn:aws:iam::111111111111:policy/my-policy&Version=2010-05-08'

To:
# note: in below, safe= <empty string>
myArn = urllib.parse.quote(arn:aws:iam::111111111111:policy/my-policy', safe='')
request_parameters = 'Action=GetPolicy&PolicyArn=' + myArn + '&Version=2010-05-08'

After making the above changes, I was able to successfully run the program in my environment.

-randy

Edited by: RandyTakeshita on Oct 6, 2019 4:47 PM

EXPERT
answered 5 years ago
0

Thanks for the reply Randy. I also tried several different "Version" options and encountered the same issue you did. My suspicion is that the 2010-05-08 version doesn't support v4 signature signing. I say that because the signature error returned doesn't actually match the error that the documentation says should be returned:

https://docs.aws.amazon.com/general/latest/gr/signature-v4-troubleshooting.html

<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

The canonical string for this request should have been 'GET / Action=ListGroupsForUser&MaxItems=100&UserName=Test&Version=2010-05-08&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential
=AKIAIOSFODNN7EXAMPLE%2F20120223%2Fus-east-1%2Fiam%2Faws4_request&X-Amz-Date=20120223T063000Z&X-Amz-SignedHeaders=host
host:iam.amazonaws.com

host
<hashed-value>'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20120223T063000Z
20120223/us-east-1/iam/aws4_request
<hashed-value>'
</Message>
  </Error>
  <RequestId>4ced6e96-5de8-11e1-aa78-a56908bdf8eb</RequestId>
</ErrorResponse>

Using the 2013-10-15 version doesn't encounter the signature signing error but then the InvalidAction comes up. But according to the docs, this is not an invalid action:

https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html

Sample Request

https://iam.amazonaws.com/?Action=GetPolicy
&PolicyArn=arn:aws:iam::123456789012:policy/S3-read-only-example-bucket
&Version=2010-05-08
&AUTHPARAMS

Replace "GetPolicy" with any other action documented here and none of those work either: https://docs.aws.amazon.com/IAM/latest/APIReference/Welcome.html

Clearly there is a discrepancy somewhere in the documentation. I also find it interesting that there aren't very many posts related to using the IAM endpoint with v4 signature signing here in the AWS forums or on stackoverflow, especially given the inconsistency of the docs. My conclusion from that is that nobody is interfacing with IAM in that way (probably using the SDKs instead), which makes me question whether it even works at all.

Thanks,
Tom

tomdaq
answered 5 years ago
0

Hi Tom,

Did you see the second part of my post. I was able to get the GetAPI call to return successfully using the same code by adding/replacing the following:

import urllib.parse

You then need to url encode the ARN, so that it will properly accepted the request parameters:

# note: in below, safe= <empty string>
myArn = urllib.parse.quote(arn:aws:iam::111111111111:policy/my-policy', safe='')
request_parameters = 'Action=GetPolicy&PolicyArn=' + myArn + '&Version=2010-05-08'

After encoding the policy Arn in my environment using the same base code you were using, this is what was returned from the call:

Response code: 200

<GetPolicyResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
  <GetPolicyResult>
    <Policy>
      <PermissionsBoundaryUsageCount>0</PermissionsBoundaryUsageCount>
      <Path>/service-role/</Path>
      <UpdateDate>2019-08-28T04:18:12Z</UpdateDate>
      <DefaultVersionId>v2</DefaultVersionId>
      <PolicyId>ANPA2WRKRNZMSHOZDHNWZ</PolicyId>
      <IsAttachable>true</IsAttachable>
      <PolicyName>AWSCodePipelineServiceRole-us-east-1-MyFirstPipeline</PolicyName>
      <Description>Policy used in trust relationship with CodePipeline</Description>
      <AttachmentCount>2</AttachmentCount>
      <Arn>arn:aws:iam::xxxxxxxxxxxxx:policy/service-role/AWSCodePipelineServiceRole-us-east-1-MyFirstPipeline</Arn>
      <CreateDate>2019-08-28T03:25:55Z</CreateDate>
    </Policy>
  </GetPolicyResult>
  <ResponseMetadata>
    <RequestId>xxxxxxxxx-e8c7-11e9-xxxxxxxxxxxxx1</RequestId>
  </ResponseMetadata>
</GetPolicyResponse>

-randy

EXPERT
answered 5 years ago
0

Ugh. Not sure why I missed that on the first read through. Thanks for your patience Randy. I'll take another crack at it with the url encoded.

Best,
Tom

tomdaq
answered 5 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions