Skip to content

Update CF URLSigner to use crypto.Signer interface#2087

Merged
aajtodd merged 1 commit intoaws:mainfrom
rem7:main
Apr 11, 2023
Merged

Update CF URLSigner to use crypto.Signer interface#2087
aajtodd merged 1 commit intoaws:mainfrom
rem7:main

Conversation

@rem7
Copy link
Copy Markdown
Contributor

@rem7 rem7 commented Apr 7, 2023

This is a proposal to update CloudFront's URLSigner to use the crypto.Signer interface.

URLSigner takes a *rsa.PrivateKey as an input to sign the pre-signed URL. If we update the function to receive the crypto.Signer interface (already implemented by rsa.PrivateKey) it allows us to use other keys to sign cloudfront URLs. For example hardware keys. This change is also more Go idiomatic.

Here is a working example of generating a pre-signed URL with a PIV key stored in a Yubikey:

package main

import (
	"crypto"
	"fmt"
	"github.com/aws/aws-sdk-go-v2/feature/cloudfront/sign"
	"github.com/go-piv/piv-go/piv"
	"log"
	"strings"
	"time"
)

func main() {

	urlstr := "https://cdn.mydomain.com/images/image1.jpg"

	var privKey crypto.Signer
	var keyID string
	keyID, privKey = getPrivateKeyFromHardware()

	signer := sign.NewURLSigner(keyID, privKey)
	signedURL, err := signer.Sign(urlstr, time.Now().Add(1*time.Minute))
	if err != nil {
		log.Fatalf("Failed to sign url, err: %s\n", err.Error())
	}
	fmt.Printf("%s\n", signedURL)

}

func getPrivateKeyFromHardware() (string, crypto.Signer) {

	keyID := "XXXXXXXXXXXX"
	fmt.Printf("getting hardware keys\n")
	cards, err := piv.Cards()
	if err != nil {
		panic(err)
	}

	var yk *piv.YubiKey
	for _, card := range cards {
		fmt.Printf("%+v\n", card)
		if strings.Contains(strings.ToLower(card), "yubikey") {
			if yk, err = piv.Open(card); err != nil {
				panic(err)
			}
			break
		}
	}

	auth := piv.KeyAuth{PIN: piv.DefaultPIN}
	cert, err := yk.Attest(piv.SlotAuthentication)
	if err != nil {
		log.Fatalf(err.Error())
	}
	priv, err := yk.PrivateKey(piv.SlotAuthentication, cert.PublicKey, auth)
	if err != nil {
		log.Fatalf(err.Error())
	}

	p, ok := priv.(crypto.Signer)
	if !ok {
		log.Fatalf("unable to cast")
	}

	return keyID, p
}

It shouldn't break compatibility with previous usage since *rsa.PrivateKey already implements crypto.Signer


For changes to files under the /codegen/aws-models folder, and manual edits to autogenerated code (e.g. /service/s3/api.go) please create an Issue instead of a PR for those type of changes.

If the PR addresses an existing bug or feature, please reference it here.

To help speed up the process and reduce the time to merge please ensure that Allow edits by maintainers is checked before submitting your PR. This will allow the project maintainers to make minor adjustments or improvements to the submitted PR, allow us to reduce the roundtrip time for merging your request.

CloudFront URLSigner uses *rsa.PrivateKey to sign the URL. If we update
the function to receive the crypto.Signer interface (already implemented
by rsa.PrivateKey) then we can use other keys to sign. For example
hardware keys.
@rem7 rem7 requested a review from a team as a code owner April 7, 2023 17:43
Copy link
Copy Markdown
Contributor

@aajtodd aajtodd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants