Skip to content

Commit

Permalink
Support for client certs towards registry server
Browse files Browse the repository at this point in the history
This commit refactors the registry options handling in the
`cmd/cosign/cli/options/registry.go` file. It introduces new flags for
specifying the X.509 CA certificate, client certificate, client key, and
server name for the connection to the registry.
This allows cosign to connect to registries that requires mTLS for
authentication.

Signed-off-by: Søren Juul <[email protected]>
  • Loading branch information
zpon committed Oct 30, 2024
1 parent 3818a1d commit ead9a9b
Showing 1 changed file with 59 additions and 2 deletions.
61 changes: 59 additions & 2 deletions cmd/cosign/cli/options/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ package options
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
"net/http"
"os"

ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login"
"github.com/chrismellard/docker-credential-acr-env/pkg/credhelper"
Expand All @@ -45,6 +47,10 @@ type RegistryOptions struct {
RefOpts ReferenceOptions
Keychain Keychain
AuthConfig authn.AuthConfig
RegistryCACert string
RegistryClientCert string
RegistryClientKey string
RegistryServerName string

// RegistryClientOpts allows overriding the result of GetRegistryClientOpts.
RegistryClientOpts []remote.Option
Expand Down Expand Up @@ -72,6 +78,18 @@ func (o *RegistryOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.AuthConfig.RegistryToken, "registry-token", "",
"registry bearer auth token")

cmd.Flags().StringVar(&o.RegistryCACert, "registry-cacert", "",
"path to the X.509 CA certificate file in PEM format to be used for the connection to the registry")

cmd.Flags().StringVar(&o.RegistryClientCert, "registry-client-cert", "",
"path to the X.509 certificate file in PEM format to be used for the connection to the registry")

cmd.Flags().StringVar(&o.RegistryClientKey, "registry-client-key", "",
"path to the X.509 private key file in PEM format to be used, together with the 'registry-client-cert' value, for the connection to the registry")

cmd.Flags().StringVar(&o.RegistryServerName, "registry-server-name", "",
"SAN name to use as the 'ServerName' tls.Config field to verify the mTLS connection to the registry")

o.RefOpts.AddFlags(cmd)
}

Expand Down Expand Up @@ -131,8 +149,9 @@ func (o *RegistryOptions) GetRegistryClientOpts(ctx context.Context) []remote.Op
opts = append(opts, remote.WithAuthFromKeychain(authn.DefaultKeychain))
}

if o.AllowInsecure {
opts = append(opts, remote.WithTransport(&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}})) // #nosec G402
tlsConfig, err := o.getTLSConfig()
if err == nil {
opts = append(opts, remote.WithTransport(&http.Transport{TLSClientConfig: tlsConfig}))
}

// Reuse a remote.Pusher and a remote.Puller for all operations that use these opts.
Expand Down Expand Up @@ -193,3 +212,41 @@ func (o *RegistryExperimentalOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().Var(&o.RegistryReferrersMode, "registry-referrers-mode",
"mode for fetching references from the registry. allowed: legacy, oci-1-1")
}

func (o *RegistryOptions) getTLSConfig() (*tls.Config, error) {
var tlsConfig tls.Config

if o.RegistryCACert != "" {
f, err := os.Open(o.RegistryCACert)
if err != nil {
return nil, err
}
defer f.Close()
caCertBytes, err := io.ReadAll(f)
if err != nil {
return nil, fmt.Errorf("unable to read CA certs from %s: %w", o.RegistryCACert, err)
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(caCertBytes) {
return nil, fmt.Errorf("no valid CA certs found in %s", o.RegistryCACert)
}
tlsConfig.RootCAs = pool
}

if o.RegistryClientCert != "" && o.RegistryClientKey != "" {
cert, err := tls.LoadX509KeyPair(o.RegistryClientCert, o.RegistryClientKey)
if err != nil {
return nil, fmt.Errorf("unable to read CA certs from cert %s, key %s: %w",
o.RegistryClientCert, o.RegistryClientKey, err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
}

if o.RegistryServerName != "" {
tlsConfig.ServerName = o.RegistryServerName
}

tlsConfig.InsecureSkipVerify = o.AllowInsecure // #nosec G402

return &tlsConfig, nil
}

0 comments on commit ead9a9b

Please sign in to comment.