NewAWSInstanceIdentity returns a metadata client and ID token validator for faking instance authentication for AWS.
(t testing.TB, instanceID string)
| 1594 | // NewAWSInstanceIdentity returns a metadata client and ID token validator for faking |
| 1595 | // instance authentication for AWS. |
| 1596 | func NewAWSInstanceIdentity(t testing.TB, instanceID string) (awsidentity.Certificates, *http.Client) { |
| 1597 | privateKey, err := rsa.GenerateKey(rand.Reader, 2048) |
| 1598 | require.NoError(t, err) |
| 1599 | |
| 1600 | document := []byte(`{"instanceId":"` + instanceID + `"}`) |
| 1601 | hashedDocument := sha256.Sum256(document) |
| 1602 | |
| 1603 | signatureRaw, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashedDocument[:]) |
| 1604 | require.NoError(t, err) |
| 1605 | signature := make([]byte, base64.StdEncoding.EncodedLen(len(signatureRaw))) |
| 1606 | base64.StdEncoding.Encode(signature, signatureRaw) |
| 1607 | |
| 1608 | certificate, err := x509.CreateCertificate(rand.Reader, &x509.Certificate{ |
| 1609 | SerialNumber: big.NewInt(2022), |
| 1610 | }, &x509.Certificate{}, &privateKey.PublicKey, privateKey) |
| 1611 | require.NoError(t, err) |
| 1612 | |
| 1613 | certificatePEM := bytes.Buffer{} |
| 1614 | err = pem.Encode(&certificatePEM, &pem.Block{ |
| 1615 | Type: "CERTIFICATE", |
| 1616 | Bytes: certificate, |
| 1617 | }) |
| 1618 | require.NoError(t, err) |
| 1619 | |
| 1620 | return awsidentity.Certificates{ |
| 1621 | awsidentity.Other: certificatePEM.String(), |
| 1622 | }, &http.Client{ |
| 1623 | Transport: roundTripper(func(r *http.Request) (*http.Response, error) { |
| 1624 | // Only handle metadata server requests. |
| 1625 | if r.URL.Host != "169.254.169.254" { |
| 1626 | return http.DefaultTransport.RoundTrip(r) |
| 1627 | } |
| 1628 | switch r.URL.Path { |
| 1629 | case "/latest/api/token": |
| 1630 | return &http.Response{ |
| 1631 | StatusCode: http.StatusOK, |
| 1632 | Body: io.NopCloser(bytes.NewReader([]byte("faketoken"))), |
| 1633 | Header: make(http.Header), |
| 1634 | }, nil |
| 1635 | case "/latest/dynamic/instance-identity/signature": |
| 1636 | return &http.Response{ |
| 1637 | StatusCode: http.StatusOK, |
| 1638 | Body: io.NopCloser(bytes.NewReader(signature)), |
| 1639 | Header: make(http.Header), |
| 1640 | }, nil |
| 1641 | case "/latest/dynamic/instance-identity/document": |
| 1642 | return &http.Response{ |
| 1643 | StatusCode: http.StatusOK, |
| 1644 | Body: io.NopCloser(bytes.NewReader(document)), |
| 1645 | Header: make(http.Header), |
| 1646 | }, nil |
| 1647 | default: |
| 1648 | panic("unhandled route: " + r.URL.Path) |
| 1649 | } |
| 1650 | }), |
| 1651 | } |
| 1652 | } |
| 1653 |