Cloud HSM Security – Part3

Cloud HSM – Part 3: Passing Secrets

As mentioned in “Cloud HSM – Part 2”, to start using an HSM deployed to a cloud, you’ll need to find a way of passing credentials such as a partition level password (or PIN) and a client side certificate to all HSM’s clients.

 

Passing this kind of secrets using common AWS mechanisms like S3 buckets, user data or baking them to AMI‘s might not be such a good idea if you consider that common “we do not trust them” mentality described in “Cloud HSM – Part1”

 

General Approach

Since a VM in any environment, including AWS, has a number of attributes (or metadata), some of which are unique for a VM, these attributes can be used to verify an instance that is making a claim by sending an assertion to a verifying party (VP).

 

In static VM environments the attributes can be used to create a VM’s fingerprint and then compare that fingerprint against a white list of all trusted fingerprints stored on a VP.

 

Creating  “white list” for all instances running in an auto-scaling group (ASG) doesn’t seem possible though due a volatile nature of some attributes such as internal/external host names and instance ID. A way around would be to make an instance verification dynamic. Fortunately, AWS API does have all necessary functions to implement a dynamic credential-less EC2 instance validation and next section provides the details.

Credential-less Dynamic EC2 Instance Verification

In this approach an EC2 client would need to collect instance parameters that are both available through a meta-data interfaces on a client, which could be considered as an asserting party (AP) and through a an AWS API on a server, which can be considered as a relying party (RP). Yet another special parameter that can be accessed on both AP and RP is an internal or external IP address, which is not exactly metadata, but can be an essential part of the instance verification process.

 

I’m intentionally using a SAML terminology here, since an authentication and authorization scenarios described below look very similar to those of SAML.

 

Here are parameters that an asserting party can fetch through a meta-data interface (e.g. through http://169.254.169.254/latest/meta-data in the ‘us-east’ region):

 

  • instance-id
  • public-hostname
  • local-hostname
  • reservation-id
  • instance-type

Their counterparts could be also retrieved through AWS API (e.g. see ec2.instance.Instance object in Python’s boto library) on RP side:

 

  • id
  • public_dns_name
  • private_dns_name
  • instance_type
  • reservation_id

IP address can be obtained through a Socket API on AP and through API’s like getRemoteAddr in JEE API or retrieved from an HTTP header ‘x-forwarded-for’ where VP’s servers are running behind proxies or load balancers.

 

Authorization

If your RP serves secrets for many different AP’s, you might need to consider implementing additional authorization controls that would not allow a single AP to get access to all possible secrets, e.g. you might want a database server to have an access to a database credentials only, while your web server might need an access to a private key to terminate SSL.

 

Using AWS Roles in these cases looks like a good solution to implement a traditional RBAC approach. You’ll basically need to assign the same role to all ASG instances using IAM console, CloudFormation or other similar tools provided by AWS. A role name would need to be submitted in an assertion created by AP and verified by RP using code like follows – basically RP would need to check if an instance that submitted a request belongs to the role provided in the assertion:

 

public boolean inRole (Instance ins, String role) {

boolean ret = false;

IamInstanceProfile prof = ins.getIamInstanceProfile();

if (prof == null)

return false;

 

String arn = prof.getArn();

ListInstanceProfilesForRoleRequest req = new ListInstanceProfilesForRoleRequest();

req.setRoleName(role);

 

AmazonIdentityManagementClient iam = new AmazonIdentityManagementClient(new         BasicAWSCredentials(appId, appSecret));

if (iam == null)

return false;

ListInstanceProfilesForRoleResult res = iam.listInstanceProfilesForRole(req);

if (res == null)

return false;

List<InstanceProfile> ipl = res.getInstanceProfiles();

for (InstanceProfile ip : ipl ) {

if (ip.getArn().equals(arn)) {

ret = true;

break;

}

}

return ret;

}

 

 

 

Security Considerations and Additional Controls

There is always a question about how reliable and secure the suggested authentication and authorization methods are. Parameters like ‘instance-type’ and ‘reservation-id’ could be considered as semi-static and as those that don’t add much entropy to the verified parameters. IP ranges can be known in advance and it will inevitably decrease the entropy as well.

 

To mitigate the risks RP implementers can consider reducing a time window during which a communication between AP and RP is allowed, e.g. an RP can check an instance start time through an AWS API and deny access if an instance was running too long.

 

Another good mitigating control could be implementing a “one-time-use” policy, meaning that an AP can get secrets from RP only one time. This can be implemented by maintaining a list of AP parameters’ hashes and denying access to those instances whose parameters’ hashes are already in the list.

Leave a Reply

Your email address will not be published. Required fields are marked *