Skip to content

Commit 9ea21bf

Browse files
authored
fix: hardcode azure instance identity intermediate certificates (#6402)
This was broken for an airgapped customer!
1 parent 6304bfb commit 9ea21bf

File tree

3 files changed

+75
-23
lines changed

3 files changed

+75
-23
lines changed

coderd/azureidentity/azureidentity.go

+73-20
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package azureidentity
22

33
import (
4-
"context"
54
"crypto/x509"
65
"encoding/base64"
76
"encoding/json"
8-
"io"
9-
"net/http"
7+
"encoding/pem"
108
"regexp"
119

1210
"go.mozilla.org/pkcs7"
@@ -23,7 +21,7 @@ type metadata struct {
2321

2422
// Validate ensures the signature was signed by an Azure certificate.
2523
// It returns the associated VM ID if successful.
26-
func Validate(ctx context.Context, signature string, options x509.VerifyOptions) (string, error) {
24+
func Validate(signature string, options x509.VerifyOptions) (string, error) {
2725
data, err := base64.StdEncoding.DecodeString(signature)
2826
if err != nil {
2927
return "", xerrors.Errorf("decode base64: %w", err)
@@ -41,24 +39,14 @@ func Validate(ctx context.Context, signature string, options x509.VerifyOptions)
4139
}
4240
if options.Intermediates == nil {
4341
options.Intermediates = x509.NewCertPool()
44-
for _, certURL := range signer.IssuingCertificateURL {
45-
req, err := http.NewRequestWithContext(ctx, "GET", certURL, nil)
46-
if err != nil {
47-
return "", xerrors.Errorf("new request %q: %w", certURL, err)
48-
}
49-
res, err := http.DefaultClient.Do(req)
50-
if err != nil {
51-
return "", xerrors.Errorf("perform request %q: %w", certURL, err)
42+
for _, cert := range certificates {
43+
block, rest := pem.Decode([]byte(cert))
44+
if len(rest) != 0 {
45+
return "", xerrors.Errorf("invalid certificate. %d bytes remain", len(rest))
5246
}
53-
data, err := io.ReadAll(res.Body)
47+
cert, err := x509.ParseCertificate(block.Bytes)
5448
if err != nil {
55-
_ = res.Body.Close()
56-
return "", xerrors.Errorf("read body %q: %w", certURL, err)
57-
}
58-
_ = res.Body.Close()
59-
cert, err := x509.ParseCertificate(data)
60-
if err != nil {
61-
return "", xerrors.Errorf("parse certificate %q: %w", certURL, err)
49+
return "", xerrors.Errorf("parse certificate: %w", err)
6250
}
6351
options.Intermediates.AddCert(cert)
6452
}
@@ -76,3 +64,68 @@ func Validate(ctx context.Context, signature string, options x509.VerifyOptions)
7664
}
7765
return metadata.VMID, nil
7866
}
67+
68+
var certificates = []string{
69+
`-----BEGIN CERTIFICATE-----
70+
MIIFWjCCBEKgAwIBAgIQDxSWXyAgaZlP1ceseIlB4jANBgkqhkiG9w0BAQsFADBa
71+
MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl
72+
clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw
73+
MDcyMTIzMDAwMFoXDTI0MTAwODA3MDAwMFowTzELMAkGA1UEBhMCVVMxHjAcBgNV
74+
BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEgMB4GA1UEAxMXTWljcm9zb2Z0IFJT
75+
QSBUTFMgQ0EgMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqYnfP
76+
mmOyBoTzkDb0mfMUUavqlQo7Rgb9EUEf/lsGWMk4bgj8T0RIzTqk970eouKVuL5R
77+
IMW/snBjXXgMQ8ApzWRJCZbar879BV8rKpHoAW4uGJssnNABf2n17j9TiFy6BWy+
78+
IhVnFILyLNK+W2M3zK9gheiWa2uACKhuvgCca5Vw/OQYErEdG7LBEzFnMzTmJcli
79+
W1iCdXby/vI/OxbfqkKD4zJtm45DJvC9Dh+hpzqvLMiK5uo/+aXSJY+SqhoIEpz+
80+
rErHw+uAlKuHFtEjSeeku8eR3+Z5ND9BSqc6JtLqb0bjOHPm5dSRrgt4nnil75bj
81+
c9j3lWXpBb9PXP9Sp/nPCK+nTQmZwHGjUnqlO9ebAVQD47ZisFonnDAmjrZNVqEX
82+
F3p7laEHrFMxttYuD81BdOzxAbL9Rb/8MeFGQjE2Qx65qgVfhH+RsYuuD9dUw/3w
83+
ZAhq05yO6nk07AM9c+AbNtRoEcdZcLCHfMDcbkXKNs5DJncCqXAN6LhXVERCw/us
84+
G2MmCMLSIx9/kwt8bwhUmitOXc6fpT7SmFvRAtvxg84wUkg4Y/Gx++0j0z6StSeN
85+
0EJz150jaHG6WV4HUqaWTb98Tm90IgXAU4AW2GBOlzFPiU5IY9jt+eXC2Q6yC/Zp
86+
TL1LAcnL3Qa/OgLrHN0wiw1KFGD51WRPQ0Sh7QIDAQABo4IBJTCCASEwHQYDVR0O
87+
BBYEFLV2DDARzseSQk1Mx1wsyKkM6AtkMB8GA1UdIwQYMBaAFOWdWTCCR1jMrPoI
88+
VDaGezq1BE3wMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
89+
KwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYI
90+
KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTA6BgNVHR8EMzAxMC+g
91+
LaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21uaXJvb3QyMDI1LmNybDAq
92+
BgNVHSAEIzAhMAgGBmeBDAECATAIBgZngQwBAgIwCwYJKwYBBAGCNyoBMA0GCSqG
93+
SIb3DQEBCwUAA4IBAQCfK76SZ1vae4qt6P+dTQUO7bYNFUHR5hXcA2D59CJWnEj5
94+
na7aKzyowKvQupW4yMH9fGNxtsh6iJswRqOOfZYC4/giBO/gNsBvwr8uDW7t1nYo
95+
DYGHPpvnpxCM2mYfQFHq576/TmeYu1RZY29C4w8xYBlkAA8mDJfRhMCmehk7cN5F
96+
JtyWRj2cZj/hOoI45TYDBChXpOlLZKIYiG1giY16vhCRi6zmPzEwv+tk156N6cGS
97+
Vm44jTQ/rs1sa0JSYjzUaYngoFdZC4OfxnIkQvUIA4TOFmPzNPEFdjcZsgbeEz4T
98+
cGHTBPK4R28F44qIMCtHRV55VMX53ev6P3hRddJb
99+
-----END CERTIFICATE-----`,
100+
`-----BEGIN CERTIFICATE-----
101+
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
130+
-----END CERTIFICATE-----`,
131+
}

coderd/azureidentity/azureidentity_test.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package azureidentity_test
22

33
import (
4-
"context"
54
"crypto/x509"
65
"testing"
76
"time"
@@ -19,7 +18,7 @@ func TestValidate(t *testing.T) {
1918
t.Parallel()
2019
ct, err := time.Parse(time.RFC3339, "2023-02-01T00:00:00Z")
2120
require.NoError(t, err)
22-
vm, err := azureidentity.Validate(context.Background(), signature, x509.VerifyOptions{
21+
vm, err := azureidentity.Validate(signature, x509.VerifyOptions{
2322
CurrentTime: ct,
2423
})
2524
require.NoError(t, err)

coderd/workspaceresourceauth.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r
3737
if !httpapi.Read(ctx, rw, r, &req) {
3838
return
3939
}
40-
instanceID, err := azureidentity.Validate(ctx, req.Signature, api.AzureCertificates)
40+
instanceID, err := azureidentity.Validate(req.Signature, api.AzureCertificates)
4141
if err != nil {
4242
httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
4343
Message: "Invalid Azure identity.",

0 commit comments

Comments
 (0)