NewGoogleInstanceIdentity returns a metadata client and ID token validator for faking instance authentication for Google Cloud. nolint:revive
(t testing.TB, instanceID string, expired bool)
| 1532 | // instance authentication for Google Cloud. |
| 1533 | // nolint:revive |
| 1534 | func NewGoogleInstanceIdentity(t testing.TB, instanceID string, expired bool) (*idtoken.Validator, *metadata.Client) { |
| 1535 | keyID, err := cryptorand.String(12) |
| 1536 | require.NoError(t, err) |
| 1537 | claims := jwt.MapClaims{ |
| 1538 | "google": map[string]interface{}{ |
| 1539 | "compute_engine": map[string]string{ |
| 1540 | "instance_id": instanceID, |
| 1541 | }, |
| 1542 | }, |
| 1543 | } |
| 1544 | if !expired { |
| 1545 | claims["exp"] = time.Now().AddDate(1, 0, 0).Unix() |
| 1546 | } |
| 1547 | token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) |
| 1548 | token.Header["kid"] = keyID |
| 1549 | privateKey, err := rsa.GenerateKey(rand.Reader, 2048) |
| 1550 | require.NoError(t, err) |
| 1551 | signedKey, err := token.SignedString(privateKey) |
| 1552 | require.NoError(t, err) |
| 1553 | |
| 1554 | // Taken from: https://github.com/googleapis/google-api-go-client/blob/4bb729045d611fa77bdbeb971f6a1204ba23161d/idtoken/validate.go#L57-L75 |
| 1555 | type jwk struct { |
| 1556 | Kid string `json:"kid"` |
| 1557 | N string `json:"n"` |
| 1558 | E string `json:"e"` |
| 1559 | } |
| 1560 | type certResponse struct { |
| 1561 | Keys []jwk `json:"keys"` |
| 1562 | } |
| 1563 | |
| 1564 | validator, err := idtoken.NewValidator(context.Background(), option.WithHTTPClient(&http.Client{ |
| 1565 | Transport: roundTripper(func(r *http.Request) (*http.Response, error) { |
| 1566 | data, err := json.Marshal(certResponse{ |
| 1567 | Keys: []jwk{{ |
| 1568 | Kid: keyID, |
| 1569 | N: base64.RawURLEncoding.EncodeToString(privateKey.N.Bytes()), |
| 1570 | E: base64.RawURLEncoding.EncodeToString(new(big.Int).SetInt64(int64(privateKey.E)).Bytes()), |
| 1571 | }}, |
| 1572 | }) |
| 1573 | require.NoError(t, err) |
| 1574 | return &http.Response{ |
| 1575 | StatusCode: http.StatusOK, |
| 1576 | Body: io.NopCloser(bytes.NewReader(data)), |
| 1577 | Header: make(http.Header), |
| 1578 | }, nil |
| 1579 | }), |
| 1580 | })) |
| 1581 | require.NoError(t, err) |
| 1582 | |
| 1583 | return validator, metadata.NewClient(&http.Client{ |
| 1584 | Transport: roundTripper(func(r *http.Request) (*http.Response, error) { |
| 1585 | return &http.Response{ |
| 1586 | StatusCode: http.StatusOK, |
| 1587 | Body: io.NopCloser(bytes.NewReader([]byte(signedKey))), |
| 1588 | Header: make(http.Header), |
| 1589 | }, nil |
| 1590 | }), |
| 1591 | }) |