oci: add tests for insecure cosign support; refactor test utils

Add tests to test Cosign support for insecure registries. Furthermore,
refactor OCI test utils to be more user friendly and enable accurate
testing of HTTPS and HTTP OCI registries by circumnavigating Docker's
automatic connection downgrade for registries hosted on localhost.

Signed-off-by: Sanskar Jaiswal <jaiswalsanskar078@gmail.com>
This commit is contained in:
Sanskar Jaiswal 2023-07-20 02:43:24 +05:30
parent 71f1080b41
commit fce7c10fc0
No known key found for this signature in database
GPG Key ID: 5982D0279C227FFD
11 changed files with 312 additions and 185 deletions

2
go.mod
View File

@ -41,6 +41,7 @@ require (
github.com/fluxcd/pkg/testserver v0.4.0
github.com/fluxcd/pkg/version v0.2.2
github.com/fluxcd/source-controller/api v1.0.0
github.com/foxcpp/go-mockdns v1.0.0
github.com/go-git/go-billy/v5 v5.4.1
github.com/go-git/go-git/v5 v5.8.1
github.com/go-logr/logr v1.2.4
@ -251,6 +252,7 @@ require (
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.50 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect

10
go.sum
View File

@ -418,6 +418,7 @@ github.com/fluxcd/pkg/testserver v0.4.0/go.mod h1:gjOKX41okmrGYOa4oOF2fiLedDAfPo
github.com/fluxcd/pkg/version v0.2.2 h1:ZpVXECeLA5hIQMft11iLp6gN3cKcz6UNuVTQPw/bRdI=
github.com/fluxcd/pkg/version v0.2.2/go.mod h1:NGnh/no8S6PyfCDxRFrPY3T5BUnqP48MxfxNRU0z8C0=
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
@ -862,7 +863,9 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU=
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
@ -1261,6 +1264,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -1341,6 +1345,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -1367,6 +1372,7 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@ -1431,6 +1437,8 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1549,6 +1557,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -1591,6 +1600,7 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=

View File

@ -2285,8 +2285,12 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) {
workspaceDir := t.TempDir()
tt.registryOpts.disableDNSMocking = true
server, err := setupRegistryServer(ctx, workspaceDir, tt.registryOpts)
g.Expect(err).NotTo(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
// Load a test chart
chartData, err := os.ReadFile(chartPath)
@ -2395,8 +2399,13 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignature(t *testing.T
g := NewWithT(t)
tmpDir := t.TempDir()
server, err := setupRegistryServer(ctx, tmpDir, registryOptions{})
server, err := setupRegistryServer(ctx, tmpDir, registryOptions{
disableDNSMocking: true,
})
g.Expect(err).ToNot(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
const (
chartPath = "testdata/charts/helmchart-0.1.0.tgz"

View File

@ -250,8 +250,12 @@ func TestHelmRepositoryOCIReconciler_authStrategy(t *testing.T) {
WithStatusSubresource(&helmv1.HelmRepository{})
workspaceDir := t.TempDir()
tt.registryOpts.disableDNSMocking = true
server, err := setupRegistryServer(ctx, workspaceDir, tt.registryOpts)
g.Expect(err).NotTo(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
obj := &helmv1.HelmRepository{
ObjectMeta: metav1.ObjectMeta{

View File

@ -18,7 +18,6 @@ package controller
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
@ -26,9 +25,7 @@ import (
"errors"
"fmt"
"math/big"
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
@ -39,7 +36,6 @@ import (
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/registry"
gcrv1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
. "github.com/onsi/gomega"
@ -80,8 +76,11 @@ func TestOCIRepository_Reconcile(t *testing.T) {
if err != nil {
g.Expect(err).ToNot(HaveOccurred())
}
t.Cleanup(func() {
regServer.Close()
})
podinfoVersions, err := pushMultiplePodinfoImages(regServer.registryHost, "6.1.4", "6.1.5", "6.1.6")
podinfoVersions, err := pushMultiplePodinfoImages(regServer.registryHost, true, "6.1.4", "6.1.5", "6.1.6")
tests := []struct {
name string
@ -146,6 +145,7 @@ func TestOCIRepository_Reconcile(t *testing.T) {
URL: tt.url,
Interval: metav1.Duration{Duration: 60 * time.Minute},
Reference: &ociv1.OCIRepositoryRef{},
Insecure: true,
},
}
obj := origObj.DeepCopy()
@ -262,8 +262,11 @@ func TestOCIRepository_Reconcile_MediaType(t *testing.T) {
if err != nil {
g.Expect(err).ToNot(HaveOccurred())
}
t.Cleanup(func() {
regServer.Close()
})
podinfoVersions, err := pushMultiplePodinfoImages(regServer.registryHost, "6.1.4", "6.1.5", "6.1.6")
podinfoVersions, err := pushMultiplePodinfoImages(regServer.registryHost, true, "6.1.4", "6.1.5", "6.1.6")
tests := []struct {
name string
@ -314,6 +317,7 @@ func TestOCIRepository_Reconcile_MediaType(t *testing.T) {
LayerSelector: &ociv1.OCILayerSelector{
MediaType: tt.mediaType,
},
Insecure: true,
},
}
@ -373,6 +377,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
craneOpts []crane.Option
secretOpts secretOptions
tlsCertSecret *corev1.Secret
insecure bool
provider string
providerImg string
want sreconcile.Result
@ -380,8 +385,10 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
assertConditions []metav1.Condition
}{
{
name: "HTTP without basic auth",
want: sreconcile.ResultSuccess,
name: "HTTP without basic auth",
want: sreconcile.ResultSuccess,
craneOpts: []crane.Option{crane.Insecure},
insecure: true,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '<revision>' for '<url>'"),
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new revision '<revision>' for '<url>'"),
@ -393,10 +400,13 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
registryOpts: registryOptions{
withBasicAuth: true,
},
craneOpts: []crane.Option{crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
insecure: true,
craneOpts: []crane.Option{
crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
crane.Insecure,
},
secretOpts: secretOptions{
username: testRegistryUsername,
@ -414,10 +424,13 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
registryOpts: registryOptions{
withBasicAuth: true,
},
craneOpts: []crane.Option{crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
insecure: true,
craneOpts: []crane.Option{
crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
crane.Insecure,
},
secretOpts: secretOptions{
username: testRegistryUsername,
@ -435,11 +448,14 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
registryOpts: registryOptions{
withBasicAuth: true,
},
wantErr: true,
craneOpts: []crane.Option{crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
insecure: true,
wantErr: true,
craneOpts: []crane.Option{
crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
crane.Insecure,
},
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.OCIPullFailedReason, "failed to determine artifact digest"),
@ -452,10 +468,13 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
registryOpts: registryOptions{
withBasicAuth: true,
},
craneOpts: []crane.Option{crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
insecure: true,
craneOpts: []crane.Option{
crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
crane.Insecure,
},
secretOpts: secretOptions{
username: "wrong-pass",
@ -467,16 +486,19 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
},
},
{
name: "HTTP registry - basic auth with invalid serviceaccount",
want: sreconcile.ResultEmpty,
wantErr: true,
name: "HTTP registry - basic auth with invalid serviceaccount",
want: sreconcile.ResultEmpty,
wantErr: true,
insecure: true,
registryOpts: registryOptions{
withBasicAuth: true,
},
craneOpts: []crane.Option{crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
craneOpts: []crane.Option{
crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
crane.Insecure,
},
secretOpts: secretOptions{
username: "wrong-pass",
@ -559,25 +581,32 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
wantErr: true,
provider: "aws",
providerImg: "oci://123456789000.dkr.ecr.us-east-2.amazonaws.com/test",
craneOpts: []crane.Option{
crane.Insecure,
},
assertConditions: []metav1.Condition{
*conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "failed to get credential from"),
},
},
{
name: "with contextual login provider and secretRef",
name: "secretRef takes precedence over provider",
want: sreconcile.ResultSuccess,
registryOpts: registryOptions{
withBasicAuth: true,
},
craneOpts: []crane.Option{crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
})},
craneOpts: []crane.Option{
crane.WithAuth(&authn.Basic{
Username: testRegistryUsername,
Password: testRegistryPassword,
}),
crane.Insecure,
},
secretOpts: secretOptions{
username: testRegistryUsername,
password: testRegistryPassword,
includeSecret: true,
},
insecure: true,
provider: "azure",
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '<revision>' for '<url>'"),
@ -607,8 +636,10 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
workspaceDir := t.TempDir()
server, err := setupRegistryServer(ctx, workspaceDir, tt.registryOpts)
g.Expect(err).NotTo(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
img, err := createPodinfoImageFromTar("podinfo-6.1.6.tar", "6.1.6", server.registryHost, tt.craneOpts...)
g.Expect(err).ToNot(HaveOccurred())
@ -664,6 +695,9 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
Name: tt.tlsCertSecret.Name,
}
}
if tt.insecure {
obj.Spec.Insecure = true
}
r := &OCIRepositoryReconciler{
Client: clientBuilder.Build(),
@ -672,7 +706,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
patchOptions: getPatchOptions(ociRepositoryReadyCondition.Owned, "sc"),
}
opts := craneOptions(ctx, true)
opts := craneOptions(ctx, tt.insecure)
opts = append(opts, crane.WithAuthFromKeychain(authn.DefaultKeychain))
repoURL, err := r.getArtifactURL(obj, opts)
g.Expect(err).To(BeNil())
@ -706,34 +740,36 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) {
func TestOCIRepository_CertSecret(t *testing.T) {
g := NewWithT(t)
srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err := createTLSServer()
tmpDir := t.TempDir()
regServer, err := setupRegistryServer(ctx, tmpDir, registryOptions{
withTLS: true,
withClientCertAuth: true,
})
g.Expect(err).ToNot(HaveOccurred())
t.Cleanup(func() {
regServer.Close()
})
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(tlsCA)
clientTLSCert, err := tls.X509KeyPair(clientPublicKey, clientPrivateKey)
g.Expect(err).ToNot(HaveOccurred())
srv.StartTLS()
defer srv.Close()
transport := &http.Transport{
TLSClientConfig: &tls.Config{},
transport := http.DefaultTransport.(*http.Transport)
transport.TLSClientConfig = &tls.Config{
RootCAs: pool,
Certificates: []tls.Certificate{clientTLSCert},
}
// Use the server cert as a CA cert, so the client trusts the
// server cert. (Only works because the server uses the same
// cert in both roles).
pool := x509.NewCertPool()
pool.AddCert(srv.Certificate())
transport.TLSClientConfig.RootCAs = pool
transport.TLSClientConfig.Certificates = []tls.Certificate{clientTLSCert}
srv.Client().Transport = transport
pi, err := createPodinfoImageFromTar("podinfo-6.1.5.tar", "6.1.5", srv.URL, []crane.Option{
crane.WithTransport(srv.Client().Transport),
pi, err := createPodinfoImageFromTar("podinfo-6.1.5.tar", "6.1.5", regServer.registryHost, []crane.Option{
crane.WithTransport(transport),
}...)
g.Expect(err).NotTo(HaveOccurred())
tlsSecretClientCert := corev1.Secret{
StringData: map[string]string{
oci.CACert: string(rootCertPEM),
oci.ClientCert: string(clientCertPEM),
oci.ClientKey: string(clientKeyPEM),
Data: map[string][]byte{
oci.CACert: tlsCA,
oci.ClientCert: clientPublicKey,
oci.ClientKey: clientPrivateKey,
},
}
@ -758,17 +794,17 @@ func TestOCIRepository_CertSecret(t *testing.T) {
url: pi.url,
digest: pi.digest,
expectreadyconition: false,
expectedstatusmessage: "unexpected status code 400 Bad Request: Client sent an HTTP request to an HTTPS server",
expectedstatusmessage: "tls: failed to verify certificate: x509:",
},
{
name: "test connection with with incorrect private key",
url: pi.url,
digest: pi.digest,
certSecret: &corev1.Secret{
StringData: map[string]string{
oci.CACert: string(rootCertPEM),
oci.ClientCert: string(clientCertPEM),
oci.ClientKey: string("invalid-key"),
Data: map[string][]byte{
oci.CACert: tlsCA,
oci.ClientCert: clientPublicKey,
oci.ClientKey: []byte("invalid-key"),
},
},
expectreadyconition: false,
@ -859,8 +895,11 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) {
tmpDir := t.TempDir()
server, err := setupRegistryServer(ctx, tmpDir, registryOptions{})
g.Expect(err).ToNot(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
podinfoVersions, err := pushMultiplePodinfoImages(server.registryHost, "6.1.4", "6.1.5", "6.1.6")
podinfoVersions, err := pushMultiplePodinfoImages(server.registryHost, true, "6.1.4", "6.1.5", "6.1.6")
img6 := podinfoVersions["6.1.6"]
img5 := podinfoVersions["6.1.5"]
@ -1001,6 +1040,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) {
URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost),
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
Insecure: true,
},
}
@ -1034,26 +1074,16 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) {
func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
g := NewWithT(t)
tmpDir := t.TempDir()
server, err := setupRegistryServer(ctx, tmpDir, registryOptions{})
g.Expect(err).ToNot(HaveOccurred())
podinfoVersions, err := pushMultiplePodinfoImages(server.registryHost, "6.1.4", "6.1.5")
g.Expect(err).ToNot(HaveOccurred())
img4 := podinfoVersions["6.1.4"]
img5 := podinfoVersions["6.1.5"]
tests := []struct {
name string
reference *ociv1.OCIRepositoryRef
insecure bool
digest string
want sreconcile.Result
wantErr bool
wantErrMsg string
shouldSign bool
keyless bool
beforeFunc func(obj *ociv1.OCIRepository)
beforeFunc func(obj *ociv1.OCIRepository, tag, revision string)
assertConditions []metav1.Condition
}{
{
@ -1061,7 +1091,6 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
reference: &ociv1.OCIRepositoryRef{
Tag: "6.1.4",
},
digest: img4.digest.String(),
shouldSign: true,
want: sreconcile.ResultSuccess,
assertConditions: []metav1.Condition{
@ -1075,7 +1104,6 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
reference: &ociv1.OCIRepositoryRef{
Tag: "6.1.5",
},
digest: img5.digest.String(),
wantErr: true,
wantErrMsg: "failed to verify the signature using provider 'cosign': no matching signatures were found for '<url>'",
want: sreconcile.ResultEmpty,
@ -1090,7 +1118,6 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
reference: &ociv1.OCIRepositoryRef{
Tag: "6.1.5",
},
digest: img5.digest.String(),
wantErr: true,
want: sreconcile.ResultEmpty,
keyless: true,
@ -1103,21 +1130,19 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
{
name: "verify failed before, removed from spec, remove condition",
reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"},
digest: img4.digest.String(),
beforeFunc: func(obj *ociv1.OCIRepository) {
beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) {
conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg")
obj.Spec.Verify = nil
obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", img4.tag, img4.digest.String())}
obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)}
},
want: sreconcile.ResultSuccess,
},
{
name: "same artifact, verified before, change in obj gen verify again",
reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"},
digest: img4.digest.String(),
shouldSign: true,
beforeFunc: func(obj *ociv1.OCIRepository) {
obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", img4.tag, img4.digest.String())}
beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) {
obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)}
// Set Verified with old observed generation and different reason/message.
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified")
// Set new object generation.
@ -1131,11 +1156,10 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
{
name: "no verify for already verified, verified condition remains the same",
reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"},
digest: img4.digest.String(),
shouldSign: true,
beforeFunc: func(obj *ociv1.OCIRepository) {
beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) {
// Artifact present and custom verified condition reason/message.
obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", img4.tag, img4.digest.String())}
obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)}
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified")
},
want: sreconcile.ResultSuccess,
@ -1144,19 +1168,17 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
},
},
{
name: "insecure registries are not supported",
name: "signed image on an insecure registry passes verification",
reference: &ociv1.OCIRepositoryRef{
Tag: "6.1.4",
Tag: "6.1.6",
},
digest: img4.digest.String(),
shouldSign: true,
insecure: true,
wantErr: true,
want: sreconcile.ResultEmpty,
want: sreconcile.ResultSuccess,
assertConditions: []metav1.Condition{
*conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '<revision>' for '<url>'"),
*conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new revision '<revision>' for '<url>'"),
*conditions.FalseCondition(sourcev1.SourceVerifiedCondition, sourcev1.VerificationError, "cosign does not support insecure registries"),
*conditions.TrueCondition(sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of revision <revision>"),
},
},
}
@ -1179,6 +1201,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
keys, err := cosign.GenerateKeyPair(pf)
g.Expect(err).ToNot(HaveOccurred())
tmpDir := t.TempDir()
err = os.WriteFile(path.Join(tmpDir, "cosign.key"), keys.PrivateBytes, 0600)
g.Expect(err).ToNot(HaveOccurred())
@ -1190,15 +1213,34 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
"cosign.pub": keys.PublicBytes,
}}
err = r.Create(ctx, secret)
if err != nil {
g.Expect(err).NotTo(HaveOccurred())
g.Expect(r.Create(ctx, secret)).NotTo(HaveOccurred())
caSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "ca-cert-cosign",
Generation: 1,
},
Data: map[string][]byte{
"caFile": tlsCA,
},
}
g.Expect(r.Create(ctx, caSecret)).ToNot(HaveOccurred())
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
workspaceDir := t.TempDir()
regOpts := registryOptions{
withTLS: !tt.insecure,
}
server, err := setupRegistryServer(ctx, workspaceDir, regOpts)
g.Expect(err).NotTo(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
obj := &ociv1.OCIRepository{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "verify-oci-source-signature-",
@ -1216,6 +1258,10 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
if tt.insecure {
obj.Spec.Insecure = true
} else {
obj.Spec.CertSecretRef = &meta.LocalObjectReference{
Name: "ca-cert-cosign",
}
}
if !tt.keyless {
@ -1226,12 +1272,15 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
obj.Spec.Reference = tt.reference
}
podinfoVersions, err := pushMultiplePodinfoImages(server.registryHost, tt.insecure, tt.reference.Tag)
g.Expect(err).ToNot(HaveOccurred())
keychain, err := r.keychain(ctx, obj)
if err != nil {
g.Expect(err).ToNot(HaveOccurred())
}
opts := craneOptions(ctx, true)
opts := craneOptions(ctx, false)
opts = append(opts, crane.WithAuthFromKeychain(keychain))
artifactURL, err := r.getArtifactURL(obj, opts)
g.Expect(err).ToNot(HaveOccurred())
@ -1250,21 +1299,22 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature(t *testing.T) {
SkipConfirmation: true,
TlogUpload: false,
Registry: coptions.RegistryOptions{Keychain: keychain, AllowInsecure: true},
Registry: coptions.RegistryOptions{Keychain: keychain, AllowInsecure: true, AllowHTTPRegistry: tt.insecure},
}, []string{artifactURL})
g.Expect(err).ToNot(HaveOccurred())
}
image := podinfoVersions[tt.reference.Tag]
assertConditions := tt.assertConditions
for k := range assertConditions {
assertConditions[k].Message = strings.ReplaceAll(assertConditions[k].Message, "<revision>", fmt.Sprintf("%s@%s", tt.reference.Tag, tt.digest))
assertConditions[k].Message = strings.ReplaceAll(assertConditions[k].Message, "<revision>", fmt.Sprintf("%s@%s", tt.reference.Tag, image.digest.String()))
assertConditions[k].Message = strings.ReplaceAll(assertConditions[k].Message, "<url>", artifactURL)
assertConditions[k].Message = strings.ReplaceAll(assertConditions[k].Message, "<provider>", "cosign")
}
if tt.beforeFunc != nil {
tt.beforeFunc(obj)
tt.beforeFunc(obj, image.tag, image.digest.String())
}
g.Expect(r.Client.Create(ctx, obj)).ToNot(HaveOccurred())
@ -1297,8 +1347,11 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) {
tmpDir := t.TempDir()
server, err := setupRegistryServer(ctx, tmpDir, registryOptions{})
g.Expect(err).ToNot(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
_, err = pushMultiplePodinfoImages(server.registryHost, "6.1.5")
_, err = pushMultiplePodinfoImages(server.registryHost, true, "6.1.5")
g.Expect(err).ToNot(HaveOccurred())
// NOTE: The following verifies if it was a noop run by checking the
@ -1431,6 +1484,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) {
Reference: &ociv1.OCIRepositoryRef{Tag: "6.1.5"},
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
Insecure: true,
},
}
@ -1709,9 +1763,11 @@ func TestOCIRepository_getArtifactURL(t *testing.T) {
tmpDir := t.TempDir()
server, err := setupRegistryServer(ctx, tmpDir, registryOptions{})
g.Expect(err).ToNot(HaveOccurred())
t.Cleanup(func() {
server.Close()
})
imgs, err := pushMultiplePodinfoImages(server.registryHost, "6.1.4", "6.1.5", "6.1.6")
imgs, err := pushMultiplePodinfoImages(server.registryHost, true, "6.1.4", "6.1.5", "6.1.6")
g.Expect(err).ToNot(HaveOccurred())
tests := []struct {
@ -1778,6 +1834,7 @@ func TestOCIRepository_getArtifactURL(t *testing.T) {
URL: tt.url,
Interval: metav1.Duration{Duration: interval},
Timeout: &metav1.Duration{Duration: timeout},
Insecure: true,
},
}
@ -2299,11 +2356,25 @@ func createPodinfoImageFromTar(tarFileName, tag, registryURL string, opts ...cra
}, nil
}
func pushMultiplePodinfoImages(serverURL string, versions ...string) (map[string]podinfoImage, error) {
func pushMultiplePodinfoImages(serverURL string, insecure bool, versions ...string) (map[string]podinfoImage, error) {
podinfoVersions := make(map[string]podinfoImage)
var opts []crane.Option
// If the registry is insecure then instruct configure an insecure HTTP client,
// otherwise add the root CA certificate since the HTTPS server is self signed.
if insecure {
opts = append(opts, crane.Insecure)
} else {
transport := http.DefaultTransport.(*http.Transport)
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(tlsCA)
transport.TLSClientConfig = &tls.Config{
RootCAs: pool,
}
opts = append(opts, crane.WithTransport(transport))
}
for i := 0; i < len(versions); i++ {
pi, err := createPodinfoImageFromTar(fmt.Sprintf("podinfo-%s.tar", versions[i]), versions[i], serverURL)
pi, err := createPodinfoImageFromTar(fmt.Sprintf("podinfo-%s.tar", versions[i]), versions[i], serverURL, opts...)
if err != nil {
return nil, err
}
@ -2362,75 +2433,6 @@ func createCert(template, parent *x509.Certificate, pub interface{}, parentPriv
return
}
func createTLSServer() (*httptest.Server, []byte, []byte, []byte, tls.Certificate, error) {
var clientTLSCert tls.Certificate
var rootCertPEM, clientCertPEM, clientKeyPEM []byte
srv := httptest.NewUnstartedServer(registry.New())
// Create a self-signed cert to use as the CA and server cert.
rootKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
rootCertTmpl, err := certTemplate()
if err != nil {
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
rootCertTmpl.IsCA = true
rootCertTmpl.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature
rootCertTmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
rootCertTmpl.IPAddresses = []net.IP{net.ParseIP("127.0.0.1")}
var rootCert *x509.Certificate
rootCert, rootCertPEM, err = createCert(rootCertTmpl, rootCertTmpl, &rootKey.PublicKey, rootKey)
if err != nil {
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
rootKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rootKey),
})
// Create a TLS cert using the private key and certificate.
rootTLSCert, err := tls.X509KeyPair(rootCertPEM, rootKeyPEM)
if err != nil {
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
// To trust a client certificate, the server must be given a
// CA cert pool.
pool := x509.NewCertPool()
pool.AddCert(rootCert)
srv.TLS = &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{rootTLSCert},
ClientCAs: pool,
}
// Create a client cert, signed by the "CA".
clientKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
clientCertTmpl, err := certTemplate()
if err != nil {
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
clientCertTmpl.KeyUsage = x509.KeyUsageDigitalSignature
clientCertTmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
_, clientCertPEM, err = createCert(clientCertTmpl, rootCert, &clientKey.PublicKey, rootKey)
if err != nil {
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
// Encode and load the cert and private key for the client.
clientKeyPEM = pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(clientKey),
})
clientTLSCert, err = tls.X509KeyPair(clientCertPEM, clientKeyPEM)
return srv, rootCertPEM, clientCertPEM, clientKeyPEM, clientTLSCert, err
}
func TestOCIContentConfigChanged(t *testing.T) {
tests := []struct {
name string

View File

@ -21,12 +21,16 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
"net"
"os"
"path/filepath"
"testing"
"time"
"github.com/foxcpp/go-mockdns"
"github.com/phayes/freeport"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"
@ -95,9 +99,11 @@ var (
)
var (
tlsPublicKey []byte
tlsPrivateKey []byte
tlsCA []byte
tlsPublicKey []byte
tlsPrivateKey []byte
tlsCA []byte
clientPublicKey []byte
clientPrivateKey []byte
)
var (
@ -114,11 +120,18 @@ type registryClientTestServer struct {
registryHost string
workspaceDir string
registryClient *helmreg.Client
dnsServer *mockdns.Server
}
type registryOptions struct {
withBasicAuth bool
withTLS bool
withBasicAuth bool
withTLS bool
withClientCertAuth bool
// Allow disbaling DNS mocking since Helm OCI doesn't yet suppot
// insecure OCI registries, which means we need Docker's automatic
// connection downgrading if the registry is hosted on localhost.
// Once Helm OCI supports insecure registries, we can get rid of this.
disableDNSMocking bool
}
func setupRegistryServer(ctx context.Context, workspaceDir string, opts registryOptions) (*registryClientTestServer, error) {
@ -150,7 +163,28 @@ func setupRegistryServer(ctx context.Context, workspaceDir string, opts registry
}
server.registryHost = fmt.Sprintf("localhost:%d", port)
config.HTTP.Addr = fmt.Sprintf("127.0.0.1:%d", port)
// Change the registry host to a host which is not localhost and
// mock DNS to map example.com to 127.0.0.1.
// This is required because Docker enforces HTTP if the registry
// is hosted on localhost/127.0.0.1.
if !opts.disableDNSMocking {
server.registryHost = fmt.Sprintf("example.com:%d", port)
// Disable DNS server logging as it is extremely chatty.
dnsLog := log.Default()
dnsLog.SetOutput(ioutil.Discard)
server.dnsServer, err = mockdns.NewServerWithLogger(map[string]mockdns.Zone{
"example.com.": {
A: []string{"127.0.0.1"},
},
}, dnsLog, false)
if err != nil {
return nil, err
}
server.dnsServer.PatchNet(net.DefaultResolver)
}
config.HTTP.Addr = fmt.Sprintf(":%d", port)
config.HTTP.DrainTimeout = time.Duration(10) * time.Second
config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
@ -178,6 +212,10 @@ func setupRegistryServer(ctx context.Context, workspaceDir string, opts registry
if opts.withTLS {
config.HTTP.TLS.Certificate = "testdata/certs/server.pem"
config.HTTP.TLS.Key = "testdata/certs/server-key.pem"
// Configure CA certificates only if client cert authentication is enabled.
if opts.withClientCertAuth {
config.HTTP.TLS.ClientCAs = []string{"testdata/certs/ca.pem"}
}
}
// setup logger options
@ -198,6 +236,13 @@ func setupRegistryServer(ctx context.Context, workspaceDir string, opts registry
return server, nil
}
func (r *registryClientTestServer) Close() {
if r.dnsServer != nil {
mockdns.UnpatchNet(net.DefaultResolver)
r.dnsServer.Close()
}
}
func TestMain(m *testing.M) {
initTestTLS()
@ -229,11 +274,13 @@ func TestMain(m *testing.M) {
panic(fmt.Sprintf("failed to create workspace directory: %v", err))
}
testRegistryServer, err = setupRegistryServer(ctx, testWorkspaceDir, registryOptions{
withBasicAuth: true,
withBasicAuth: true,
disableDNSMocking: true,
})
if err != nil {
panic(fmt.Sprintf("Failed to create a test registry server: %v", err))
}
defer testRegistryServer.Close()
if err := (&GitRepositoryReconciler{
Client: testEnv,
@ -355,6 +402,14 @@ func initTestTLS() {
if err != nil {
panic(err)
}
clientPrivateKey, err = os.ReadFile("testdata/certs/client-key.pem")
if err != nil {
panic(err)
}
clientPublicKey, err = os.ReadFile("testdata/certs/client.pem")
if err != nil {
panic(err)
}
}
func newTestStorage(s *testserver.HTTPServer) (*Storage, error) {

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
all: server-key.pem
all: server-key.pem client-key.pem
ca-key.pem: ca-csr.json
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
@ -28,3 +28,13 @@ server-key.pem: server-csr.json ca-config.json ca-key.pem
server-csr.json | cfssljson -bare server
sever.pem: server-key.pem
server.csr: server-key.pem
client-key.pem: client-csr.json ca-config.json ca-key.pem
cfssl gencert \
-ca=ca.pem \
-ca-key=ca-key.pem \
-config=ca-config.json \
-profile=web-servers \
client-csr.json | cfssljson -bare client
client.pem: client-key.pem
client.csr: client-key.pem

View File

@ -0,0 +1,9 @@
{
"CN": "example.com",
"hosts": [
"127.0.0.1",
"localhost",
"example.com",
"www.example.com"
]
}

View File

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICpqb1p1TH98yoFXEEt6JmWc/Snb8NaYyz8jfTOVDBLOoAoGCCqGSM49
AwEHoUQDQgAERjzob4CCuyv+cYPyTYCPHwGuqSNGNuX3UGWpxvzwEqjYEWiePlOz
eJLk4DWaVX8CmVakNLsK/EHnBv9ErG7QYQ==
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,8 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBHDCBwwIBADAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABEY86G+Agrsr/nGD8k2Ajx8BrqkjRjbl91Blqcb88BKo2BFo
nj5Ts3iS5OA1mlV/AplWpDS7CvxB5wb/RKxu0GGgSzBJBgkqhkiG9w0BCQ4xPDA6
MDgGA1UdEQQxMC+CCWxvY2FsaG9zdIILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxl
LmNvbYcEfwAAATAKBggqhkjOPQQDAgNIADBFAiAHmtr9fDDx5eyFfY7r5m8xA4Wh
Jm+TB6/czvXRNNOKzAIhAN7ln6BpneEm2oqIBGqvfc3pETC6jdGJxCfYw+X+7von
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB7DCCAZKgAwIBAgIUPJmKtZ6CfSxybx2BSsVS5EVun0swCgYIKoZIzj0EAwIw
GTEXMBUGA1UEAxMOZXhhbXBsZS5jb20gQ0EwHhcNMjMwNzE5MTExMzAwWhcNMzMw
NzE2MTExMzAwWjAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABEY86G+Agrsr/nGD8k2Ajx8BrqkjRjbl91Blqcb88BKo2BFo
nj5Ts3iS5OA1mlV/AplWpDS7CvxB5wb/RKxu0GGjgbowgbcwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
MB0GA1UdDgQWBBTgAyCQoH/EJqz/nY5DJa/uvWWshzAfBgNVHSMEGDAWgBQGyUiU
1QEZiMAqjsnIYTwZ4yp5wzA4BgNVHREEMTAvgglsb2NhbGhvc3SCC2V4YW1wbGUu
Y29tgg93d3cuZXhhbXBsZS5jb22HBH8AAAEwCgYIKoZIzj0EAwIDSAAwRQIgKSJH
YvhKiXcUUzRoL6FsXQeAlhemSg3lD9se+BhRF8ECIQDx2UpWFLDe5NOPqhrcR1Sd
haFriAG8eR1yD3u3nJvY6g==
-----END CERTIFICATE-----