NewAzureInstanceIdentity returns a metadata client and ID token validator for faking instance authentication for Azure. It builds a realistic 3-level certificate chain (Root CA -> Intermediate -> Signing Cert) to match the real Azure trust hierarchy.
(t testing.TB, instanceID string)
| 1656 | // a realistic 3-level certificate chain (Root CA -> Intermediate -> |
| 1657 | // Signing Cert) to match the real Azure trust hierarchy. |
| 1658 | func NewAzureInstanceIdentity(t testing.TB, instanceID string) (azureidentity.Options, *http.Client) { |
| 1659 | // Root CA (self-signed, trusted). |
| 1660 | rootKey, err := rsa.GenerateKey(rand.Reader, 2048) |
| 1661 | require.NoError(t, err) |
| 1662 | rootTmpl := &x509.Certificate{ |
| 1663 | SerialNumber: big.NewInt(1), |
| 1664 | Subject: pkix.Name{CommonName: "Test Root CA"}, |
| 1665 | NotBefore: time.Now().Add(-time.Hour), |
| 1666 | NotAfter: time.Now().AddDate(10, 0, 0), |
| 1667 | IsCA: true, |
| 1668 | BasicConstraintsValid: true, |
| 1669 | KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, |
| 1670 | } |
| 1671 | rootDER, err := x509.CreateCertificate(rand.Reader, rootTmpl, rootTmpl, &rootKey.PublicKey, rootKey) |
| 1672 | require.NoError(t, err) |
| 1673 | rootCert, err := x509.ParseCertificate(rootDER) |
| 1674 | require.NoError(t, err) |
| 1675 | |
| 1676 | // Intermediate CA (signed by root). |
| 1677 | interKey, err := rsa.GenerateKey(rand.Reader, 2048) |
| 1678 | require.NoError(t, err) |
| 1679 | interTmpl := &x509.Certificate{ |
| 1680 | SerialNumber: big.NewInt(2), |
| 1681 | Subject: pkix.Name{CommonName: "Test Intermediate CA"}, |
| 1682 | NotBefore: time.Now().Add(-time.Hour), |
| 1683 | NotAfter: time.Now().AddDate(5, 0, 0), |
| 1684 | IsCA: true, |
| 1685 | BasicConstraintsValid: true, |
| 1686 | KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, |
| 1687 | } |
| 1688 | interDER, err := x509.CreateCertificate(rand.Reader, interTmpl, rootCert, &interKey.PublicKey, rootKey) |
| 1689 | require.NoError(t, err) |
| 1690 | interCert, err := x509.ParseCertificate(interDER) |
| 1691 | require.NoError(t, err) |
| 1692 | |
| 1693 | // Signing cert (leaf, signed by intermediate). |
| 1694 | signKey, err := rsa.GenerateKey(rand.Reader, 2048) |
| 1695 | require.NoError(t, err) |
| 1696 | signTmpl := &x509.Certificate{ |
| 1697 | SerialNumber: big.NewInt(3), |
| 1698 | Subject: pkix.Name{CommonName: "metadata.azure.com"}, |
| 1699 | NotBefore: time.Now().Add(-time.Hour), |
| 1700 | NotAfter: time.Now().AddDate(1, 0, 0), |
| 1701 | } |
| 1702 | signDER, err := x509.CreateCertificate(rand.Reader, signTmpl, interCert, &signKey.PublicKey, interKey) |
| 1703 | require.NoError(t, err) |
| 1704 | signCert, err := x509.ParseCertificate(signDER) |
| 1705 | require.NoError(t, err) |
| 1706 | |
| 1707 | // Build PKCS7 signed data with only the signing cert. |
| 1708 | signed, err := pkcs7.NewSignedData([]byte(`{"vmId":"` + instanceID + `"}`)) |
| 1709 | require.NoError(t, err) |
| 1710 | err = signed.AddSigner(signCert, signKey, pkcs7.SignerInfoConfig{}) |
| 1711 | require.NoError(t, err) |
| 1712 | signatureRaw, err := signed.Finish() |
| 1713 | require.NoError(t, err) |
| 1714 | signature := make([]byte, base64.StdEncoding.EncodedLen(len(signatureRaw))) |
| 1715 | base64.StdEncoding.Encode(signature, signatureRaw) |