ebourg / jsign

Java implementation of Microsoft Authenticode for signing Windows executables, installers & scripts
https://ebourg.github.io/jsign
Apache License 2.0
250 stars 107 forks source link

AWS KMS with service-linked role #147

Closed vmal-altium closed 1 year ago

vmal-altium commented 1 year ago

My requirement is to use the KMS option of jsign from an EC2 instance with an appropriate role, without having to manually specify credentials in the command line.

As a result, I was wondering whether there are specific reasons not to use the AWS SDK rather than API (aside from the extra dependency). The SDK covers more options in terms of credentials (see DefaultCredentialsProvider), and hides the request-signing business.

I have done a prototype with the SDK, which seems to work, and I wanted to get your view on how to take this forward.

ebourg commented 1 year ago

I try to avoid the AWS SDK due to its size, the REST API is simple enough to be called directly.

How do you call the API with a service linked role? Can you get an access key and a secret key with the AWS CLI?

vmal-altium commented 1 year ago

jsign-5.0-SNAPSHOT.jar indeed inflates from 1.0MB to 3.7MB when using the AWS SDK instead...

The SDK uses the InstanceProfileCredentialsProvider class to load temporary credentials from the Amazon EC2 metadata service.

Under the hood, InstanceProfileCredentialsProvider uses IMDSv2, which boils down to something like this:

TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ROLE=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials)
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE

I could parse the JSON output to get the storepass string that jsign currently expects:

jq  '.AccessKeyId+"|"+.SecretAccessKey+"|"+.Token'

The advantage of the SDK version is that it encapsulates all that logic (and more for other scenarios like ECS containers,...), but I agree on the increased size 😄

ebourg commented 1 year ago

The input variables are the endpoint (169.254.169.254 in this example) and the name of the role?

vmal-altium commented 1 year ago

169.254.169.254 is a fixed IP address that AWS uses to offer the metadata service to all EC2 instances, so that is not going to change, and can be essentially hardcoded.

The role is assigned externally to the EC2 instance (AWS console or so), and defines the permissions it has to interact with AWS services (KMS here). The metadata service (IMDS) can be queried from within the instance to know the currently assigned role name, and from that, credentials to make requests to the other AWS services.

So there is no input variable in this case; credentials are available from the fact that the code is run from within an authorised EC2 instance. I would still offer the possibility to pass credentials through the command line (as now), but if not provided, then it would try to use other means to get credentials.

ebourg commented 1 year ago

Thank you for the details. So this means that if we are able to detect that Jsign runs on an EC2 instance, the storepass parameter could be omitted and the CLI syntax could be as simple as:

jsign --storetype AWS --keystore eu-west-3 \
      --alias 12345678-abcd-1234-cdef-1234567890ab

When storetype is set to AWS and storepass isn't specified, Jsign could attempt to fetch the token at http://169.254.169.254/latest/api/token.

I don't have an AWS account to test that unfortunately. If someone is willing to implement and test the credentials lookup I'll merge it.

ebourg commented 1 year ago

The implementation has been merged with a few changes. The new AmazonCredentials class centralizes the access to the credentials and hides the fetching logic, It supports the EC2 instance credentials and credentials set in the environment variables. It could be extended to also load the credentials from a local ~/.aws/credentials file as used by the AWS CLI.

Could you test and confirm I haven't broken anything?

vmal-altium commented 1 year ago

Sorry for the delay. I have just tested the 5.0 release, and it's all fine for the AWS credentials from IMDS, as well as detecting mismatches between private/public keys. Thanks a lot for the mention in the release notes.

ebourg commented 1 year ago

Thanks again for the help!