Skip to content

Commit

Permalink
Added mTLS options
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Block <andy.block@gmail.com>
  • Loading branch information
sabre1041 committed Apr 12, 2024
1 parent bf18775 commit 135ebc2
Show file tree
Hide file tree
Showing 2 changed files with 276 additions and 7 deletions.
11 changes: 11 additions & 0 deletions cmd/oras/internal/option/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ import (
type Remote struct {
DistributionSpec
CACertFilePath string
CertFilePath string
KeyFilePath string
Insecure bool
Configs []string
Username string
Expand Down Expand Up @@ -111,6 +113,8 @@ func (opts *Remote) ApplyFlagsWithPrefix(fs *pflag.FlagSet, prefix, description
return *plainHTTP, fs.Changed(plainHTTPFlagName)
}
fs.StringVarP(&opts.CACertFilePath, flagPrefix+"ca-file", "", "", "server certificate authority file for the remote "+notePrefix+"registry")
fs.StringVarP(&opts.CertFilePath, flagPrefix+"cert-file", "", "", "client certificate authority file for the remote "+notePrefix+"registry")
fs.StringVarP(&opts.KeyFilePath, flagPrefix+"key-file", "", "", "client private key file for the remote "+notePrefix+"registry")
fs.StringArrayVarP(&opts.resolveFlag, flagPrefix+"resolve", "", nil, "customized DNS for "+notePrefix+"registry, formatted in `host:port:address[:address_port]`")
fs.StringArrayVarP(&opts.Configs, flagPrefix+"registry-config", "", nil, "`path` of the authentication file for "+notePrefix+"registry")
fs.StringArrayVarP(&opts.headerFlags, flagPrefix+"header", shortHeader, nil, "add custom headers to "+notePrefix+"requests")
Expand Down Expand Up @@ -191,6 +195,13 @@ func (opts *Remote) tlsConfig() (*tls.Config, error) {
return nil, err
}
}
if opts.CertFilePath != "" && opts.KeyFilePath != "" {
cert, err := tls.LoadX509KeyPair(opts.CertFilePath, opts.KeyFilePath)
if err != nil {
return nil, err

Check warning on line 201 in cmd/oras/internal/option/remote.go

View check run for this annotation

Codecov / codecov/patch

cmd/oras/internal/option/remote.go#L201

Added line #L201 was not covered by tests
}
config.Certificates = []tls.Certificate{cert}
}
return config, nil
}

Expand Down
272 changes: 265 additions & 7 deletions cmd/oras/internal/option/remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@ package option
import (
"context"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"reflect"
"strings"
"testing"

"github.com/sirupsen/logrus"
Expand All @@ -43,9 +45,213 @@ var testTagList = struct {
Tags: []string{"tag"},
}

// localhostServerCert is a PEM-encoded TLS cert with SAN IPs
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
// adapted from src/crypto/tls:
// go run generate_cert.go --rsa-bits 4096 --host 127.0.0.1,::1,oras.land --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
var localhostServerCert = []byte(`-----BEGIN CERTIFICATE-----
MIIFMjCCAxqgAwIBAgIRAPzEFsDt4E8GxCNLsF76j18wDQYJKoZIhvcNAQELBQAw
DzENMAsGA1UEChMET1JBUzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2MDAw
MFowDzENMAsGA1UEChMET1JBUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBAKcbdhkxvx0CXeDZuEz3kKgVsQpyNRXP0AWKS8FqxbVe+NLDZl9jzDtQBvCt
BW3UjgIxnUMG5tGrtTHvzLJNfkX4DvTkWUOiLu8VxcAT6vG5v87xyrq86taMLrCm
o42wHpJNETPlCtJquGEADPHs4D+EOAMWfaCvy5rEYt6JD/oy6/VehPInE3Q634NK
98OD25xykOtq1sIvoZibIgq8T5GlmBrxAb+axfhX8tp7NEJ4wvOUorEnww3cZJb6
7Q6ijvzEWT2RD58prR7l4yvsb+HmSEWoJcd5JZd0CUiVIM44L3E4qllXJ2vwT9Fv
dXwfwx29zQ9VVLlNibPzJ4a0ZEIhi8ZMGtoLR7gEhsM+PraZz+2TL5APJWI2TRZk
A2m7v2DMv4ZbUOOy1OivOIwJqA6k9lsm2oMOPrTIZ0pZIXu1bmF0/Z8js4LNx5HU
4SsIHYpj1efH27YgjfBY9ROX3iITQsKyUpCpF9z845tzbdw66tRTazLvumNVrdlz
fKceFDbmgi6uz/lILSppy/kzKkoaY6+NTogW6Kg/2icPH8rg6LpxHpQlAHqABB8t
25w39DQoD5sPGt/ChEX5Pb0bLUWlnl+6vKa4vfctiZ2DevGePLrK1lW+L4K05yCF
CpqPWKvm75aVs9HZGFbIsJTF2B4IQnYmm9IhqFuSh1sZBf2dAgMBAAGjgYYwgYMw
DgYDVR0PAQH/BAQDAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFHSvVlBTGCMOip+SGZ7QO+0isE8tMCwGA1UdEQQlMCOC
CW9yYXMubGFuZIcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsF
AAOCAgEANrLbIqIe+7hd51BZDJn1tSE/Ld/kgwJ8mBZdB6XF2WLoCgVOx9VGmJH3
Z09b0KqJpp3s2HgYJNc5AHNAyH/u1E4HUAyKajuI420Z/GdV3CK2uwcp5mkkF4qK
ew6PEYUQRjZf95k+6T8VR8P9O0kiigr4Srgqal2EolSf8e27EO+JERueVn3NgRms
FrJv2+LILKFfBt5o9S1D5xNa9qu6NfW3x6F0VwaBxgjnUpqePUQaFzSSZ+VXmKmh
rx7I8PaNrac5DslDtmpVj/z9RwuExPZAB+/utocUWmSU0epTyqXiKQy8sgSVhsVe
yyClPguXtuD3IV/i5uAcSVf1xrCSSifkYnmhfMA5lUgjOmDuY/Am4f2DJcjBETb2
hsac+8C6IppGrZOuOinTp5ZIocFKjNxcjGnmqxk0hWW6GuF4truKSEicIiBvoqZp
rearfvDbM6g4CobowU1S6vNkUc2ziCE23AmoY65V3Vnmj72p5Mi7P932jzf2qEA1
vCGB9hrxO3Yr5wkOXUGQI/nU+KQTCdf/4j4kUh+N1pByGMPG05GrOpmy1Tems9sp
BddDm85WsThpxTf+Rp5xp5/FQh72eigkXa/ezeldEGI/rhKRJJtujU6Kq6SoKX29
YRSTpM+MeFPJDVffVUFXQrxnGIXRzxhx49wMSoKFYR/225exX1c=
-----END CERTIFICATE-----`)

// localhostServerKey is the private key for localhostServerCert.
var localhostServerKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
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
MIoYYNqQ9tdHlLwyViIAgaZvunID5Q==
-----END RSA TESTING KEY-----`))

// localhostClientCert is a PEM-encoded TLS cert with SAN IPs
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
// adapted from src/crypto/tls:
// go run generate_cert.go --rsa-bits 4096 --host 127.0.0.1,::1,oras.land --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
var localhostClientCert = []byte(`-----BEGIN CERTIFICATE-----
MIIFMjCCAxqgAwIBAgIRAMow8iHaN1G+R2GjMyOC5LQwDQYJKoZIhvcNAQELBQAw
DzENMAsGA1UEChMET1JBUzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2MDAw
MFowDzENMAsGA1UEChMET1JBUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBAM01pjqP4xZmX8zAT5p7k90FpbZ1W5S8qLIkajvzzoGeksSH2FgG+rXK+yJ6
TZo74a5ZKOUHtdjurRTvMgCjCvFIWv0wqnkeVFmXDLXQZiEamatPInGF2vJnv9BW
O4sLdopyXxAd4BQiC7ot8JO2PRiLubPRHDp2xExsDbqiAPU49qvwVFEfdnU+nHdt
jmmcZKzeD4iiu9DeZZJhv9h+OEZNXyHNDFV9/CRNrwO9Xfx8OvTZNklSYOyF0YER
nr1mmdQBZ4SCYYGBBdWvjkII7hZNkT9/qOBB2p/JXquF+6GYGruVAfAYRfADXCg1
+T+M8X1XZuja5wIxvwbH8JV5RXN/vk9mt36EXGSuesAOlVYKnv3Ux1bxPSuWT3RU
47GM/8vmelopHTIUtcLPnNFk3xlWyjNx7Sv67CxWniJFuOXrqrI0DLj/EQzOxoMa
uD0WO0BXHHNSFF7dhrd6FTNu3EppYFWQt9wBsZ8jgDRsHh2GeuyEo1YlSSB+rvs4
20w9cCSYGduJ4BKqcGRDY6c9QCRgZ5VWs+feS3awBK6Gx4mWh4bjM1ICGbiPeiw9
2DeHjjAqunlMN0z7Pa28lE0GE3rZpcwxtS3Blnm6Q/lDbCBmOWrGH4ngQ02HeaY4
t7xUayaiz3lkZjcTrdZa9OxHLZwmGmqY7JB3X/TReePr9jT5AgMBAAGjgYYwgYMw
DgYDVR0PAQH/BAQDAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA8GA1UdEwEB/wQF
MAMBAf8wHQYDVR0OBBYEFDpedkP2AJKzCgJkZf9PpIOIXRHbMCwGA1UdEQQlMCOC
CW9yYXMubGFuZIcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsF
AAOCAgEAGtRCFG27HZqu2kz0IW6UuYUKv7gqtN4/47At3CHFAd3UAAErKrammwFH
fWB4zy4MU9fHMgJhc8ctZg0QR8f1fnpN8MlnmV3fqEbUVwbZov2x46wgwLD7PRZM
NPh+Z2reFRE2VNi+rZsqcTAPy48FQ0WdCpzQheeonincLuY6GYV1DjhHn3HNFqkn
lslS5FRRkkLxXLgr0p0fNAEUMqce16VjVcM2BbEuCRvlepZZF7uVvEOQvtEMJSdF
APmUUsS7x6jvIxmZpxzanBmu2u4kQwTMW4UDpkNVwdCPGEM/SAdQUkqOYIQU807n
93QrXXY3XIlDp7U6xA2AfZQ9fiV7cDul06IzsXcisTeK8uSfhHRROqbt9MotiIve
xEVTyh4tfue7kFowq7wd3H2UTSLgByfJBkEAN+BTDUpEwT7gZOVcxbzpkL+vyPfr
CVdIbE9ZlBzCc5i0RWaMrEJfFy93a7ZptlXytfQM/MFOlKaIDXFjoylmkW9IhrFd
Ger/gr4AFzD7AQRF9+c0Cu4je3A+ob9R0CvvwEthjQCrOWjVgbUxR+qMVNCtCRwk
Bt4BEd7qH0bM8EAY7BwPEP7vfvp7iblp0FNNLYQCbxd0eK69Tb2olzQRKKyNpqls
/cqUr8lpYbGAdorLJSeCj8EZ7+o9ZJXbxilkcMl3R8wV8mn5Olw=
-----END CERTIFICATE-----`)

// localhostClientKey is the private key for localhostClientCert.
var localhostClientKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
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
tFAnaOX7ziz6wrV8TmuU9ZdGX+Aw+g==
-----END RSA TESTING KEY-----`))

func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }

func loadTestingTLSConfig() *tls.Config {

clientCertPool := x509.NewCertPool()
clientCertPool.AppendCertsFromPEM(localhostClientCert)

tlsConfig := &tls.Config{
Certificates: []tls.Certificate{loadTestingCert(localhostServerCert, localhostServerKey)},
ClientAuth: tls.VerifyClientCertIfGiven,
ClientCAs: clientCertPool,
}

return tlsConfig
}

func loadTestingCert(certificate, key []byte) tls.Certificate {
cert, err := tls.X509KeyPair(certificate, key)
if err != nil {
panic(fmt.Sprintf("Unable to load testing certificate: %v", err))
}

return cert

}

func TestMain(m *testing.M) {
// Test server
ts = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ts = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
p := r.URL.Path
m := r.Method
switch {
Expand All @@ -57,6 +263,8 @@ func TestMain(m *testing.M) {
}
}
}))
ts.TLS = loadTestingTLSConfig()
ts.StartTLS()
defer ts.Close()
m.Run()
}
Expand Down Expand Up @@ -116,7 +324,7 @@ func TestRemote_authClient_skipTlsVerify(t *testing.T) {

func TestRemote_authClient_CARoots(t *testing.T) {
caPath := filepath.Join(t.TempDir(), "oras-test.pem")
if err := os.WriteFile(caPath, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ts.Certificate().Raw}), 0644); err != nil {
if err := os.WriteFile(caPath, localhostServerCert, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}

Expand Down Expand Up @@ -174,7 +382,7 @@ func plainHTTPNotSpecified() (plainHTTP bool, fromFlag bool) {

func TestRemote_NewRegistry(t *testing.T) {
caPath := filepath.Join(t.TempDir(), "oras-test.pem")
if err := os.WriteFile(caPath, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ts.Certificate().Raw}), 0644); err != nil {
if err := os.WriteFile(caPath, localhostServerCert, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}

Expand Down Expand Up @@ -203,15 +411,63 @@ func TestRemote_NewRegistry(t *testing.T) {

func TestRemote_NewRepository(t *testing.T) {
caPath := filepath.Join(t.TempDir(), "oras-test.pem")
if err := os.WriteFile(caPath, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ts.Certificate().Raw}), 0644); err != nil {
if err := os.WriteFile(caPath, localhostServerCert, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}
opts := struct {
Remote
Common
}{
Remote{
CACertFilePath: caPath,
plainHTTP: plainHTTPNotSpecified,
},
Common{},
}

uri, err := url.ParseRequestURI(ts.URL)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
repo, err := opts.NewRepository(uri.Host+"/"+testRepo, opts.Common, logrus.New())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err = repo.Tags(context.Background(), "", func(got []string) error {
want := []string{"tag"}
if len(got) != len(testTagList.Tags) || !reflect.DeepEqual(got, want) {
return fmt.Errorf("expect: %v, got: %v", testTagList.Tags, got)
}
return nil
}); err != nil {
t.Fatalf("unexpected error: %v", err)
}
}

func TestRemote_NewRepositoryMTLS(t *testing.T) {
caPath := filepath.Join(t.TempDir(), "oras-test.pem")
if err := os.WriteFile(caPath, localhostServerCert, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}

clientCertPath := filepath.Join(t.TempDir(), "oras-test-client.pem")
if err := os.WriteFile(clientCertPath, localhostClientCert, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}

clientKeyPath := filepath.Join(t.TempDir(), "oras-test-client.key")
if err := os.WriteFile(clientKeyPath, localhostClientKey, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}

opts := struct {
Remote
Common
}{
Remote{
CACertFilePath: caPath,
CertFilePath: clientCertPath,
KeyFilePath: clientKeyPath,
plainHTTP: plainHTTPNotSpecified,
},
Common{},
Expand All @@ -238,11 +494,11 @@ func TestRemote_NewRepository(t *testing.T) {

func TestRemote_NewRepository_Retry(t *testing.T) {
caPath := filepath.Join(t.TempDir(), "oras-test.pem")
if err := os.WriteFile(caPath, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ts.Certificate().Raw}), 0644); err != nil {
if err := os.WriteFile(caPath, localhostServerCert, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}
retries, count := 3, 0
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
if count < retries {
http.Error(w, "error", http.StatusTooManyRequests)
Expand All @@ -253,6 +509,8 @@ func TestRemote_NewRepository_Retry(t *testing.T) {
http.Error(w, "error encoding", http.StatusBadRequest)
}
}))
ts.TLS = loadTestingTLSConfig()
ts.StartTLS()
defer ts.Close()
opts := struct {
Remote
Expand Down

0 comments on commit 135ebc2

Please sign in to comment.