Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Commit

Permalink
signing server cmd updates (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
jschicktanz authored Jun 17, 2022
1 parent baa99f8 commit 5674313
Show file tree
Hide file tree
Showing 21 changed files with 157 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ component-cli component-archive signatures sign signing-server BASE_URL COMPONEN
```
--allow-plain-http allows the fallback to http if the oci registry does not support https
--cc-config string path to the local concourse config file
--config string config file which contains the signing server configuration
--client-cert string [OPTIONAL] path to a file containing the client certificate in PEM format for authenticating to the server
--force [OPTIONAL] force overwrite of already existing component descriptors
-h, --help help for signing-server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--private-key string [OPTIONAL] path to a file containing the private key for the provided client certificate in PEM format
--recursive [OPTIONAL] recursively sign and upload all referenced component descriptors
--registry-config string path to the dockerconfig.json with the oci registry authentication information
--root-ca-certs string [OPTIONAL] path to a file containing additional root ca certificates in PEM format. if empty, the system root ca certificate pool is used
--server-url string url where the signing server is running, e.g. https://localhost:8080
--signature-name string name of the signature
--skip-access-types strings [OPTIONAL] comma separated list of access types that will not be digested and signed
--upload-base-url string target repository context to upload the signed cd
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/containerd/containerd v1.5.5
github.com/docker/cli v20.10.0-rc1+incompatible
github.com/drone/envsubst v1.0.2
github.com/gardener/component-spec/bindings-go v0.0.64
github.com/gardener/component-spec/bindings-go v0.0.65
github.com/gardener/image-vector v0.10.0
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v0.4.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/gardener/component-spec/bindings-go v0.0.52/go.mod h1:kQFMTWowNAp9tOp6aImQa/NoLzfvX29jN5Qgud9rpQU=
github.com/gardener/component-spec/bindings-go v0.0.64 h1:5OrwY3D7NjH+nnXCVhUtAvE56/LaMKO2av1Z5aK6/Pw=
github.com/gardener/component-spec/bindings-go v0.0.64/go.mod h1:hwdDN2xZhFxv1vdamShz3/29Nqjx4UQlpxjyBZAZh4M=
github.com/gardener/component-spec/bindings-go v0.0.65 h1:HHczHWEJUXYcaKr+UWGvXFTHYONeSdlIqlj0T73POiw=
github.com/gardener/component-spec/bindings-go v0.0.65/go.mod h1:hwdDN2xZhFxv1vdamShz3/29Nqjx4UQlpxjyBZAZh4M=
github.com/gardener/image-vector v0.10.0 h1:Ysg3hxfiGUG/doajiZ0nQuUaJYwfO5BZCOcijL3tRuo=
github.com/gardener/image-vector v0.10.0/go.mod h1:32SHGcbmmueeK9VkawsFcEbsoENXQPIuuYiFBUP+vMQ=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
Expand Down
6 changes: 3 additions & 3 deletions pkg/commands/componentarchive/remote/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,13 @@ func (o *ShowOptions) Complete(args []string) error {
}

if len(o.BaseUrl) == 0 {
return errors.New("the base url must be defined")
return errors.New("the base url must be provided")
}
if len(o.ComponentName) == 0 {
return errors.New("a component name must be defined")
return errors.New("a component name must be provided")
}
if len(o.Version) == 0 {
return errors.New("a component's Version must be defined")
return errors.New("a component version must be provided")
}
return nil
}
Expand Down
9 changes: 4 additions & 5 deletions pkg/commands/componentarchive/signature/add_digests.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,16 @@ func (o *AddDigestsOptions) Complete(args []string) error {
}

if len(o.BaseUrl) == 0 {
return errors.New("the base url must be defined")
return errors.New("a base url must be provided")
}
if len(o.ComponentName) == 0 {
return errors.New("a component name must be defined")
return errors.New("a component name must be provided")
}
if len(o.Version) == 0 {
return errors.New("a component version must be defined")
return errors.New("a component version must be provided")
}

if o.UploadBaseUrl == "" {
return errors.New("upload-base-url must be defined")
return errors.New("a upload base url must be provided")
}

return nil
Expand Down
6 changes: 3 additions & 3 deletions pkg/commands/componentarchive/signature/check_digests.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ func (o *CheckDigestsOptions) Complete(args []string) error {
}

if len(o.BaseUrl) == 0 {
return errors.New("the base url must be defined")
return errors.New("a base url must be provided")
}
if len(o.ComponentName) == 0 {
return errors.New("a component name must be defined")
return errors.New("a component name must be provided")
}
if len(o.Version) == 0 {
return errors.New("a component's Version must be defined")
return errors.New("a component version must be provided")
}
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/componentarchive/signature/sign/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (o *RSASignOptions) Complete(args []string) error {
}

if o.PathToPrivateKey == "" {
return errors.New("a path to private key file must be given as flag")
return errors.New("a path to a private key file must be provided")
}

return nil
Expand Down
20 changes: 16 additions & 4 deletions pkg/commands/componentarchive/signature/sign/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

ociopts "github.com/gardener/component-cli/ociclient/options"
"github.com/gardener/component-cli/pkg/commands/constants"
"github.com/gardener/component-cli/pkg/components"
"github.com/gardener/component-cli/pkg/logger"
"github.com/gardener/component-cli/pkg/signatures"
)
Expand Down Expand Up @@ -62,6 +63,8 @@ type GenericSignOptions struct {

// OciOptions contains all exposed options to configure the oci client.
OciOptions ociopts.Options

SignedRef string
}

//Complete validates the arguments and flags from the command line
Expand All @@ -81,20 +84,27 @@ func (o *GenericSignOptions) Complete(args []string) error {
}

if len(o.BaseUrl) == 0 {
return errors.New("the base url must be defined")
return errors.New("a base url must be provided")
}
if len(o.ComponentName) == 0 {
return errors.New("a component name must be defined")
return errors.New("a component name must be provided")
}
if len(o.Version) == 0 {
return errors.New("a component's Version must be defined")
return errors.New("a component version must be provided")
}
if o.UploadBaseUrlForSigned == "" {
return errors.New("upload-base-url must be defined")
return errors.New("a upload base url must be provided")
}
if o.SignatureName == "" {
return errors.New("a signature name must be provided")
}

signedRef, err := components.OCIRef(cdv2.NewOCIRegistryRepository(o.UploadBaseUrlForSigned, ""), o.ComponentName, o.Version)
if err != nil {
return fmt.Errorf("invalid reference for signed component descriptor: %w", err)
}
o.SignedRef = signedRef

return nil
}

Expand Down Expand Up @@ -171,5 +181,7 @@ func (o *GenericSignOptions) SignAndUploadWithSigner(ctx context.Context, log lo
return fmt.Errorf("unable to upload component descriptor: %w", err)
}
}

log.Info(fmt.Sprintf("Successfully uploaded signed component descriptor at %s", o.SignedRef))
return nil
}
17 changes: 11 additions & 6 deletions pkg/commands/componentarchive/signature/sign/signing_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
)

type SigningServerSignOptions struct {
// SigningServerConfigPath path to the config file containing signing server configuration
SigningServerConfigPath string
ServerURL string
ClientCertPath string
PrivateKeyPath string
RootCACertsPath string

GenericSignOptions
}
Expand Down Expand Up @@ -51,7 +53,7 @@ func NewSigningServerSignCommand(ctx context.Context) *cobra.Command {
}

func (o *SigningServerSignOptions) Run(ctx context.Context, log logr.Logger, fs vfs.FileSystem) error {
signer, err := signatures.NewSigningServerSignerFromConfigFile(o.SigningServerConfigPath)
signer, err := signatures.NewSigningServerSigner(o.ServerURL, o.ClientCertPath, o.PrivateKeyPath, o.RootCACertsPath)
if err != nil {
return fmt.Errorf("unable to create signing server signer: %w", err)
}
Expand All @@ -63,14 +65,17 @@ func (o *SigningServerSignOptions) Complete(args []string) error {
return err
}

if o.SigningServerConfigPath == "" {
return errors.New("a config file which contains the signing server configuration must be given as flag")
if o.ServerURL == "" {
return errors.New("a server url must be provided")
}

return nil
}

func (o *SigningServerSignOptions) AddFlags(fs *pflag.FlagSet) {
o.GenericSignOptions.AddFlags(fs)
fs.StringVar(&o.SigningServerConfigPath, "config", "", "config file which contains the signing server configuration")
fs.StringVar(&o.ServerURL, "server-url", "", "url where the signing server is running, e.g. https://localhost:8080")
fs.StringVar(&o.ClientCertPath, "client-cert", "", "[OPTIONAL] path to a file containing the client certificate in PEM format for authenticating to the server")
fs.StringVar(&o.PrivateKeyPath, "private-key", "", "[OPTIONAL] path to a file containing the private key for the provided client certificate in PEM format")
fs.StringVar(&o.RootCACertsPath, "root-ca-certs", "", "[OPTIONAL] path to a file containing additional root ca certificates in PEM format. if empty, the system root ca certificate pool is used")
}
2 changes: 1 addition & 1 deletion pkg/commands/componentarchive/signature/verify/rsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (o *RSAVerifyOptions) Complete(args []string) error {
return err
}
if o.PathToPublicKey == "" {
return errors.New("a path to public key file must be given as flag")
return errors.New("a path to a public key file must be provided")
}

return nil
Expand Down
6 changes: 3 additions & 3 deletions pkg/commands/componentarchive/signature/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ func (o *GenericVerifyOptions) Complete(args []string) error {
}

if len(o.BaseUrl) == 0 {
return errors.New("the base url must be defined")
return errors.New("a base url must be provided")
}
if len(o.ComponentName) == 0 {
return errors.New("a component name must be defined")
return errors.New("a component name must be provided")
}
if len(o.Version) == 0 {
return errors.New("a component's version must be defined")
return errors.New("a component version must be provided")
}
if o.SignatureName == "" {
return errors.New("a signature name must be provided")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (o *X509CertificateVerifyOptions) Complete(args []string) error {
}

if o.certPath == "" {
return errors.New("a path to a certificate file must be given as flag")
return errors.New("a path to a certificate file must be provided")
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/ctf/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (o *AddOptions) Complete(args []string) error {
// Validate validates push options
func (o *AddOptions) Validate() error {
if len(o.CTFPath) == 0 {
return errors.New("a path to the component descriptor must be defined")
return errors.New("a path to the component descriptor must be provided")
}

if len(o.ComponentArchives) == 0 {
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/ctf/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (o *PushOptions) Complete(args []string) error {
// Validate validates push options
func (o *PushOptions) Validate() error {
if len(o.CTFPath) == 0 {
return errors.New("a path to the component descriptor must be defined")
return errors.New("a path to the component descriptor must be provided")
}
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/componentarchive/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (o *BuilderOptions) Default() {
// Validate validates the component archive builder options.
func (o *BuilderOptions) Validate() error {
if len(o.ComponentArchivePath) == 0 {
return errors.New("a component archive path must be defined")
return errors.New("a component archive path must be provided")
}

if len(o.Name) != 0 {
Expand Down
68 changes: 53 additions & 15 deletions pkg/signatures/signing_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package signatures

import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
Expand All @@ -14,28 +16,42 @@ import (

cdv2 "github.com/gardener/component-spec/bindings-go/apis/v2"
cdv2signatures "github.com/gardener/component-spec/bindings-go/apis/v2/signatures"
"sigs.k8s.io/yaml"
)

const (
AcceptHeader = "Accept"
// http header
AcceptHeader = "Accept"
HashAlgorithmHeader = "X-Hash-Algorithm"
SignatureAlgorithmHeader = "X-Signature-Algorithm"
)

type SigningServerSigner struct {
Url string `json:"url"`
Username string `json:"username"`
Password string `json:"password"`
ServerURL string
ClientCert *tls.Certificate
RootCACerts []byte
}

func NewSigningServerSignerFromConfigFile(configFilePath string) (*SigningServerSigner, error) {
configBytes, err := ioutil.ReadFile(configFilePath)
if err != nil {
return nil, fmt.Errorf("unable to read config file: %w", err)
func NewSigningServerSigner(serverURL, clientCertPath, privateKeyPath, rootCACertsPath string) (*SigningServerSigner, error) {
signer := SigningServerSigner{
ServerURL: serverURL,
}
var signer SigningServerSigner
if err := yaml.Unmarshal(configBytes, &signer); err != nil {
return nil, fmt.Errorf("unable to parse config yaml: %w", err)

if clientCertPath != "" {
clientCert, err := tls.LoadX509KeyPair(clientCertPath, privateKeyPath)
if err != nil {
return nil, fmt.Errorf("unable to load client certificate: %w", err)
}
signer.ClientCert = &clientCert
}

if rootCACertsPath != "" {
rootCACerts, err := ioutil.ReadFile(rootCACertsPath)
if err != nil {
return nil, fmt.Errorf("unable to read root ca certificates file: %w", err)
}
signer.RootCACerts = rootCACerts
}

return &signer, nil
}

Expand All @@ -45,14 +61,36 @@ func (signer *SigningServerSigner) Sign(componentDescriptor cdv2.ComponentDescri
return nil, fmt.Errorf("unable to hex decode hash: %w", err)
}

req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/sign", signer.Url), bytes.NewBuffer(decodedHash))
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/sign", signer.ServerURL), bytes.NewBuffer(decodedHash))
if err != nil {
return nil, fmt.Errorf("unable to build http request: %w", err)
}
req.Header.Add(AcceptHeader, cdv2.MediaTypePEM)
req.SetBasicAuth(signer.Username, signer.Password)
req.Header.Add(HashAlgorithmHeader, digest.HashAlgorithm)
req.Header.Add(SignatureAlgorithmHeader, cdv2.RSAPKCS1v15)

var certPool *x509.CertPool
if len(signer.RootCACerts) > 0 {
certPool = x509.NewCertPool()
if ok := certPool.AppendCertsFromPEM(signer.RootCACerts); !ok {
return nil, fmt.Errorf("unable to append root ca certificates to cert pool")
}
}

clientCerts := []tls.Certificate{}
if signer.ClientCert != nil {
clientCerts = append(clientCerts, *signer.ClientCert)
}

client := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
Certificates: clientCerts,
},
},
}

client := http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("unable to send http request: %w", err)
Expand Down
5 changes: 2 additions & 3 deletions pkg/signatures/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/gardener/component-cli/pkg/logger"

cdv2 "github.com/gardener/component-spec/bindings-go/apis/v2"
v2 "github.com/gardener/component-spec/bindings-go/apis/v2"
cdv2Sign "github.com/gardener/component-spec/bindings-go/apis/v2/signatures"
cdoci "github.com/gardener/component-spec/bindings-go/oci"
ocispecv1 "github.com/opencontainers/image-spec/specs-go/v1"
Expand Down Expand Up @@ -68,7 +67,7 @@ func RecursivelyAddDigestsToCd(cd *cdv2.ComponentDescriptor, repoContext cdv2.OC
res := res
if _, ok := skipAccessTypes[res.Access.Type]; ok {
log := logger.Log.WithValues("componentDescriptor", cd, "resource.name", res.Name, "resource.version", res.Version, "resource.extraIdentity", res.ExtraIdentity)
log.Info(fmt.Sprintf("adding %s digest to resource based on skip-access-type", v2.ExcludeFromSignature))
log.Info(fmt.Sprintf("adding %s digest to resource based on skip-access-type", cdv2.ExcludeFromSignature))

res.Digest = cdv2.NewExcludeFromSignatureDigest()
cd.Resources[i] = res
Expand All @@ -83,7 +82,7 @@ func RecursivelyAddDigestsToCd(cd *cdv2.ComponentDescriptor, repoContext cdv2.OC
return cdsWithHashes, nil
}

func UploadCDPreservingLocalOciBlobs(ctx context.Context, cd v2.ComponentDescriptor, targetRepository cdv2.OCIRegistryRepository, ociClient ociclient.ExtendedClient, cache ociCache.Cache, blobResolvers map[string]ctf.BlobResolver, force bool, log logr.Logger) error {
func UploadCDPreservingLocalOciBlobs(ctx context.Context, cd cdv2.ComponentDescriptor, targetRepository cdv2.OCIRegistryRepository, ociClient ociclient.ExtendedClient, cache ociCache.Cache, blobResolvers map[string]ctf.BlobResolver, force bool, log logr.Logger) error {
// check if the component descriptor already exists and skip if not forced to overwrite
if !force {
cdresolver := cdoci.NewResolver(ociClient)
Expand Down
Loading

0 comments on commit 5674313

Please sign in to comment.