{"id":64,"date":"2014-06-29T18:28:09","date_gmt":"2014-06-29T18:28:09","guid":{"rendered":"http:\/\/credelius.com\/credelius\/?p=64"},"modified":"2014-06-29T18:39:13","modified_gmt":"2014-06-29T18:39:13","slug":"cloud-hsm-security-part3","status":"publish","type":"post","link":"https:\/\/credelius.com\/credelius\/?p=64","title":{"rendered":"Cloud HSM Security &#8211; Part3"},"content":{"rendered":"<h2>Cloud HSM &#8211; Part 3: Passing Secrets<\/h2>\n<p>As mentioned in <a href=\"http:\/\/ogryb.blogspot.com\/2013\/07\/cloudhsm-part-2-how-to-and-automation.html\" data-blogger-escaped-target=\"_blank\">&#8220;Cloud HSM &#8211; Part 2&#8221;<\/a>, to start using an HSM deployed to a cloud, you&#8217;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&#8217;s clients.<\/p>\n<p>&nbsp;<\/p>\n<p>Passing this kind of secrets using common AWS mechanisms like <a href=\"http:\/\/aws.amazon.com\/s3\/\" data-blogger-escaped-target=\"_blank\">S3 buckets<\/a>, <a href=\"http:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/AESDG-chapter-instancedata.html\" data-blogger-escaped-target=\"_blank\">user data<\/a> or baking them to <a href=\"https:\/\/aws.amazon.com\/amis\" data-blogger-escaped-target=\"_blank\">AMI<\/a>&#8216;s might not be such a good idea if you consider that common &#8220;we do not trust them&#8221; mentality described in <a href=\"http:\/\/ogryb.blogspot.com\/2013\/06\/why-cloud-hsm-can-revolutionize-aws.html\" data-blogger-escaped-target=\"_blank\">&#8220;Cloud HSM &#8211; Part1&#8221;<\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>General Approach<\/h2>\n<p>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).<\/p>\n<p>&nbsp;<\/p>\n<p>In static VM environments the attributes can be used to create a VM&#8217;s fingerprint and then compare that fingerprint against a white list of all trusted fingerprints stored on a VP.<\/p>\n<p>&nbsp;<\/p>\n<p>Creating\u00a0 &#8220;white list&#8221; for all instances running in an auto-scaling group (<a href=\"http:\/\/aws.amazon.com\/autoscaling\/\" data-blogger-escaped-target=\"_blank\">ASG<\/a>) doesn&#8217;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 <a href=\"http:\/\/aws.amazon.com\/ec2\/\" data-blogger-escaped-target=\"_blank\">EC2<\/a> instance validation and next section provides the details.<\/p>\n<h2>Credential-less Dynamic EC2 Instance Verification<\/h2>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n<p>I&#8217;m intentionally using a <a href=\"https:\/\/www.oasis-open.org\/committees\/tc_home.php?wg_abbrev=security\" data-blogger-escaped-target=\"_blank\">SAML<\/a> terminology here, since an authentication and authorization scenarios described below look very similar to those of SAML.<\/p>\n<p>&nbsp;<\/p>\n<p>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 &#8216;us-east&#8217; region):<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>instance-id<\/li>\n<li>public-hostname<\/li>\n<li>local-hostname<\/li>\n<li>reservation-id<\/li>\n<li>instance-type<\/li>\n<\/ul>\n<p>Their counterparts could be also retrieved through AWS API (e.g. see ec2.instance.Instance object in Python&#8217;s <a href=\"http:\/\/code.google.com\/p\/boto\/\" data-blogger-escaped-target=\"_blank\">boto<\/a> library) on RP side:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>id<\/li>\n<li>public_dns_name<\/li>\n<li>private_dns_name<\/li>\n<li>instance_type<\/li>\n<li>reservation_id<\/li>\n<\/ul>\n<p>IP address can be obtained through a <a href=\"http:\/\/broken\/http:\/\/www.w3.org\/TR\/2013\/WD-raw-sockets-20130514\/\" data-blogger-escaped-target=\"_blank\">Socket API<\/a> on AP and through API&#8217;s like getRemoteAddr in JEE API or retrieved from an HTTP header &#8216;x-forwarded-for&#8217; where VP&#8217;s servers are running behind proxies or load balancers.<\/p>\n<p>&nbsp;<\/p>\n<h2>Authorization<\/h2>\n<p>If your RP serves secrets for many different AP&#8217;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.<\/p>\n<p>&nbsp;<\/p>\n<p>Using AWS Roles in these cases looks like a good solution to implement a traditional <a href=\"https:\/\/en.wikipedia.org\/wiki\/Role-based_access_control\" data-blogger-escaped-target=\"_blank\">RBAC<\/a> approach. You&#8217;ll basically need to assign the same role to all ASG instances using <a href=\"http:\/\/aws.amazon.com\/iam\/\" data-blogger-escaped-target=\"_blank\">IAM console<\/a>, 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 &#8211; basically RP would need to check if an instance that submitted a request belongs to the role provided in the assertion:<\/p>\n<p>&nbsp;<\/p>\n<p><strong>public<\/strong> <strong>boolean<\/strong> inRole (Instance ins, String role) {<\/p>\n<p><strong>boolean<\/strong> ret = <strong>false<\/strong>;<\/p>\n<p>IamInstanceProfile prof = ins.getIamInstanceProfile();<\/p>\n<p><strong>if<\/strong> (prof == <strong>null<\/strong>)<\/p>\n<p><strong>return<\/strong> <strong>false<\/strong>;<\/p>\n<p>&nbsp;<\/p>\n<p>String arn = prof.getArn();<\/p>\n<p>ListInstanceProfilesForRoleRequest req = <strong>new<\/strong> ListInstanceProfilesForRoleRequest();<\/p>\n<p>req.setRoleName(role);<\/p>\n<p>&nbsp;<\/p>\n<p>AmazonIdentityManagementClient iam = <strong>new<\/strong> AmazonIdentityManagementClient(<strong>new<\/strong> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0BasicAWSCredentials(appId, appSecret));<\/p>\n<p><strong>if<\/strong> (iam == <strong>null<\/strong>)<\/p>\n<p><strong>return<\/strong> <strong>false<\/strong>;<\/p>\n<p>ListInstanceProfilesForRoleResult res = iam.listInstanceProfilesForRole(req);<\/p>\n<p><strong>if<\/strong> (res == <strong>null<\/strong>)<\/p>\n<p><strong>return<\/strong> <strong>false<\/strong>;<\/p>\n<p>List&lt;InstanceProfile&gt; ipl = res.getInstanceProfiles();<\/p>\n<p><strong>for<\/strong> (InstanceProfile ip : ipl ) {<\/p>\n<p><strong>if<\/strong> (ip.getArn().equals(arn)) {<\/p>\n<p>ret = <strong>true<\/strong>;<\/p>\n<p><strong>break<\/strong>;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p><strong>return<\/strong> ret;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h2>Security Considerations and Additional Controls<\/h2>\n<p>There is always a question about how reliable and secure the suggested authentication and authorization methods are. Parameters like &#8216;instance-type&#8217; and &#8216;reservation-id&#8217; could be considered as semi-static and as those that don&#8217;t add much entropy to the verified parameters. IP ranges can be known in advance and it will inevitably decrease the entropy as well.<\/p>\n<p>&nbsp;<\/p>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n<p>Another good mitigating control could be implementing a &#8220;one-time-use&#8221; policy, meaning that an AP can get secrets from RP only one time. This can be implemented by maintaining a list of AP parameters&#8217; hashes and denying access to those instances whose parameters&#8217; hashes are already in the list.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cloud HSM &#8211; Part 3: Passing Secrets As mentioned in &#8220;Cloud HSM &#8211; Part 2&#8221;, to start using an HSM deployed to a cloud, you&#8217;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&#8217;s clients. &nbsp; Passing this kind of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=\/wp\/v2\/posts\/64"}],"collection":[{"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=64"}],"version-history":[{"count":1,"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=\/wp\/v2\/posts\/64\/revisions"}],"predecessor-version":[{"id":65,"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=\/wp\/v2\/posts\/64\/revisions\/65"}],"wp:attachment":[{"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=64"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=64"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/credelius.com\/credelius\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=64"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}