Closed cyberark-bizdev closed 6 years ago
What I need to understand better is how the AWS IAM role associates to a Conjur role (Host).
What I'd expect to see is something like: The id of the Conjur Host must match the IAM role provided by the signed request
OR
The Conjur Host has an annotation authn-iam/role
, and the request must be signed with that role.
I think that an end-to-end example in the specification here would help to flesh this out. Please expand the specification by showing:
authenticate
URL and what each parameter will beauthenticate
privilege but is not running under the right IAM role.authenticate
privilege on the webservice.@kgilpin here my attempt to explain it.
In AWS, IAM Roles will be created for the different kind (or maybe even different criteria as well) of host instances (which could be EC2 hosts or lambda functions to start.)
These IAM roles will be instance profile
roles, that means that Amazon automatically makes those instances to assume those roles when they are initiated/started.
The instance profile roles will need to be protected by AWS using policies, to guarantee they can only be assumed by the particular instances. A trusted policy for an EC2 instance profile will look like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
While the one for lambda function will look like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
By properly securing the AWS trusted policies and permissions, we should rely on the instance roles to only be assumed by the target instances.
In the Conjur policy by using the iam_allowed_roles annotation, we can define which instances will be able to authenticate to Conjur. We use the headers of a GetCallerIdentity URL request, to validate from the Conjur side the host authenticating is an instance that has assumed one of the roles from the list of roles allowed by the Conjur web service.
The flow from an EC2 instance will be like:
The EC2 instance when started immediately assumes the role defined in AWS as its instance profile role.
The EC2 instance signs a getCallerIdentity URL request and passes the headers as the body of the authentication URL to Conjur. In the Conjur authentication URL it also passes the service name to be matched against the web service defined in Conjur, and the "hostname" that it will assume under Conjur.
During the authentication on the Conjur side, we perform the following validations:
IF all conditions pass, then we return a JSON hash (with token) for subsequent API calls.
Responding directly each of your questions:
What is configured in AWS: Instance Profile Roles will be defined in AWS, and properly secured to allow only the right instances to assume them.
How a host is configured in the Conjur policy
---
!policy id: conjur/authn-iam/aws body:
!webservice
!layer clients
!host id: ec2-host annotations: iam_allowed_roles:
!permit role: !layer clients privilege: [ read, authenticate ] resource: !webservice
!grant role: !layer clients member: !host ec2-host
&secrets
!variable secret-access-key
!variable access-key-id
!variable secret
!permit resource: !variable secret privileges: [read, execute] role: !layer clients
how the client will build the authenticate
URL and what each parameter will be
The client signs a getCallerIdentity URL request and passes the headers as the body of the authenticate URL for conjur. In the Conjur authenticate URL it also passes the service name to be matched against the web service defined in Conjur, and the "hostname" / host role that it will assume under Conjur.
How an unauthorized Host will be rejected. Show various scenarios in which this happens: Any failure of the following conditions will result in a rejection:
How I cannot impersonate an IAM role of a different AWS account. We validate against full ARN (Amazon Resource Name) instead of names which could be replicated in different AWS accounts. The ARN contains the AWS account ID.
An example successful run will look like:
[ec2-user@ip-172-31-3-12 ~]$
[ec2-user@ip-172-31-3-12 ~]$ export aws_signed_headers=`./sign_request.rb`
[ec2-user@ip-172-31-3-12 ~]$
[ec2-user@ip-172-31-3-12 ~]$ echo $aws_signed_headers
{"host":"sts.amazonaws.com","x-amz-date":"20180504T014727Z","x-amz-security-token":"FQoDYXdzEFIaDCFHQ6dey4pm779E0iK3A/YOaYPACECBB3nO6cuJq80RYXKSPvTZw4DtmmjVD1JeKYDxr7jO8L2uHQjR9s3xbnsZIuiwjtC4ig53/CM6kAFGeJM+3FBPgB37k42HB3H2c2xIPjVyDCLnc65C8pZTQ4Znv18GhNHjU7AG+o4hSbFJ31WF0Nx0PY/nVp1Aadrd4j6eAYJgYE5w1Sg3R0u6+VI7PXySOEj18Kb8JbjhtDNjiHFgs+2CL9I0RCln7sqThqgdGIs0ofePDQvzzTMGNn27RFQlD8iVKBZhwVpYIfpZRi2Cz0ZHkNWaIk64ytoqmd9MqCerc/awqQNmRN0zOkk4cXvW7wGWzaHMVW/jM6Fmus8xdSONB8MaMuH6CDVljLPqOeL3xh7mLGynl7kHpCHn++byb8SA3nYDatfX1L2aDMLDR27BlNz0PodmN9hAP99pymk3xbHJC6ZXaiXV5Ov3yVahxkQSH4j2De3yyws6uni+AsVzK/Ot0wB5N10k6yMqRIGjRM0o97fOjcHPG1MJ3w94dkVPAkrPAkFkoMr/+BESS4PkjKdR2yFTosJfYszCDRBUjTTX/j5AH9kHMjj/9Tkq6Hsomeau1wU=","x-amz-content-sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","authorization":"AWS4-HMAC-SHA256 Credential=ASIAILI5BVGKITQSP27A/20180504/us-east-1/sts/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=ffd028dc350493c3991a0a5b861cbc47bfb2b9e60faa1bdd3495c808364f67e9"}
[ec2-user@ip-172-31-3-12 ~]$
[ec2-user@ip-172-31-3-12 ~]$
[ec2-user@ip-172-31-3-12 ~]$ export conjur_token=`curl -s -X POST --data "$aws_signed_headers" 73.202.253.45:3000/authn-iam/aws/cucumber/host%2fconjur%2fauthn-iam%2faws%2fec2-host/authenticate | base64 | tr -d "\r\n"`
[ec2-user@ip-172-31-3-12 ~]$
[ec2-user@ip-172-31-3-12 ~]$ echo $conjur_token
eyJwcm90ZWN0ZWQiOiJleUpoYkdjaU9pSmpiMjVxZFhJdWIzSm5MM05zYjNOcGJHOHZkaklpTENKcmFXUWlPaUkwTldNek56RTBNakZpTlRWa1lUQXlOMkppWmpObE9ERmpOemhsWldFM1l5SjkiLCJwYXlsb2FkIjoiZXlKemRXSWlPaUpvYjNOMEwyTnZibXAxY2k5aGRYUm9iaTFwWVcwdllYZHpMMlZqTWkxb2IzTjBJaXdpYVdGMElqb3hOVEkxTXprNE5EYzRmUT09Iiwic2lnbmF0dXJlIjoiSzJCd0p6UlFZeE5CaDhCSTFzSi1CV2R5M2N4ZmdWUEgyWU5kMGFROWVUa0RzNlhIbHRieElXekp4Z2VWNnBTN0hrdmhmelJ4QkNPUGU1VDY2dDAtNUpCZTBuaDVzNlFrYk92dXZzSDVlc2xqTm5Za3FoamdOcV8wQmFQbk5Cc091ZHV4U28xcGV3SnZseTA3X0phMUVHSlZYanlsSlN6ZTRnaUg0N19HRXpnZXdHSU5kMXZvUW5jaUpVNWFEYTJURVJVZGdjOExqcndYZERFcWpVU1pMRVZWZDVpNHc2bXdMdGRyQ2NuWGhua1NxY2xUMGZnRUlZRlU3OWZUazdCN01sOUZDejNOYjYzbTdxU09ab0dyWWFGdU9lWXd1Q3J5ZHo5TTB3Y0ktemFiZ2Z3aE1NMHI3UjBsalhTNGF2R2RDM2cxMV9abVBUdkE4eFllQ1huMFFZUHkzU21pTFNDS0tuVFN0UnFSY2VYTGN0XzFSSDh0V0Y1WnZGY2NRMk1zIn0=
[ec2-user@ip-172-31-3-12 ~]$
[ec2-user@ip-172-31-3-12 ~]$
[ec2-user@ip-172-31-3-12 ~]$ echo `curl -s -X GET -H "Authorization: Token token=\"$conjur_token\"" 73.202.253.45:3000/secrets/cucumber/variable/conjur/authn-iam/aws/secret`
TOPSECRET2
[ec2-user@ip-172-31-3-12 ~]$
sign_request.rb code here:
!/usr/bin/env ruby
require 'aws-sigv4'
require 'aws-sdk'
credentials = Aws::InstanceProfileCredentials.new
url = 'https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15'
service = 'sts'
region = 'us-east-1'
http_method = 'GET'
signer = Aws::Sigv4::Signer.new(
service: service,
region: region,
credentials_provider: credentials
)
signature = signer.sign_request(
http_method: http_method,
url: url
)
puts signature.headers.to_json
Is the sign_request.rb
subject to a replay attack? In other words, if I somehow obtain a signed request (possibly an old one) can I use it to obtain a Conjur access token? Is there a date stamp or other replay defense?
@kgilpin the signed request is time based.... the time/date-stamp is part of the signature. They expire within 5 minutes I believe.
Rationale for closing this issue
This issue has been reopened with a new, updated description as #542
Description
IAM authentication allows a
host
to authenticate with Conjur using headers from a signed URL request (against AWS IAM) rather than their Conjur credentials. IAM authentication works exactly as regular authentication, returning a JSON hash if thehost
authenticates successfully.The idea of IAM authentication is the ability to use IAM Roles as a way to authenticate EC2 instances, Lambda Functions, etc. to Conjur by relying on AWS built-in authorization/authentication mechanism.
The signed URL request headers sent to Conjur for authentication allows Conjur to verify whether AWS recognizes the caller identity; in fact, the URL is a getCallerIdentity from AWS STS (Security Token Service.)
Workflow To enable the authenticator, the
CONJUR_AUTHENTICATORS
environment variable must be set on any Conjur node that may be servicing the authentication request, and it must include the stringauthn-iam/<authenticator-name>
in its comma-separated list of allowed authenticators (for example,CONJUR_AUTHENTICATORS=authn-iam/aws,authn-iam/o365
).The authenticator webservice must be declared in Conjur policy:
Once the authenticator has been properly configured, a user will be able to configure their environment to use IAM authorization through the Conjur CLI client, UI, or when using Summon by setting the
CONJUR_AUTHN_URL
environment variable:To successfully use the IAM authenticator to authenticate to Conjur (if entitled to do so in Conjur policy), a host (instance) needs their Conjur hostname to pass the following criteria: