Skip to content

Commit 4d5d7f8

Browse files
authored
feat(cli): support custom CA certificates (#1017)
Signed-off-by: Miguel Martinez Trivino <[email protected]>
1 parent c141736 commit 4d5d7f8

File tree

13 files changed

+202
-13
lines changed

13 files changed

+202
-13
lines changed

app/artifact-cas/configs/config.devel.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ server:
1313
# Some unary RPCs are slow, so we need to increase the timeout
1414
# For example, Azure Blob Storage describe takes more than 1 second to respond sometimes
1515
timeout: 5s
16+
# tls_config:
17+
# certificate: "../../devel/devkeys/selfsigned/cas.crt"
18+
# private_key: "../../devel/devkeys/selfsigned/cas.key"
1619
http_metrics:
1720
addr: 0.0.0.0:5001
1821

app/cli/cmd/artifact.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,13 @@ func wrappedArtifactConn(cpConn *grpc.ClientConn, role pb.CASCredentialsServiceG
5050
logger.Warn().Msg("API contacted in insecure mode")
5151
}
5252

53-
return grpcconn.New(viper.GetString(confOptions.CASAPI.viperKey), resp.Result.Token, flagInsecure)
53+
var opts = []grpcconn.Option{
54+
grpcconn.WithInsecure(flagInsecure),
55+
}
56+
57+
if caFilePath := viper.GetString(confOptions.CASCA.viperKey); caFilePath != "" {
58+
opts = append(opts, grpcconn.WithCAFile(caFilePath))
59+
}
60+
61+
return grpcconn.New(viper.GetString(confOptions.CASAPI.viperKey), resp.Result.Token, opts...)
5462
}

app/cli/cmd/attestation_add.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func newAttestationAddCmd() *cobra.Command {
6868
&action.AttestationAddOpts{
6969
ActionsOpts: actionOpts,
7070
CASURI: viper.GetString(confOptions.CASAPI.viperKey),
71+
CASCAPath: viper.GetString(confOptions.CASCA.viperKey),
7172
ConnectionInsecure: flagInsecure,
7273
RegistryServer: registryServer,
7374
RegistryUsername: registryUsername,

app/cli/cmd/config.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2023 The Chainloop Authors.
2+
// Copyright 2024 The Chainloop Authors.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@ import (
2121

2222
// Map of all the possible configuration options that we expect viper to handle
2323
var confOptions = struct {
24-
authToken, controlplaneAPI, CASAPI *confOpt
24+
authToken, controlplaneAPI, CASAPI, controlplaneCA, CASCA *confOpt
2525
}{
2626
authToken: &confOpt{
2727
viperKey: "auth.token",
@@ -30,10 +30,18 @@ var confOptions = struct {
3030
viperKey: "control-plane.API",
3131
flagName: "control-plane",
3232
},
33+
controlplaneCA: &confOpt{
34+
viperKey: "control-plane.api-ca",
35+
flagName: "control-plane-ca",
36+
},
3337
CASAPI: &confOpt{
3438
viperKey: "artifact-cas.API",
3539
flagName: "artifact-cas",
3640
},
41+
CASCA: &confOpt{
42+
viperKey: "artifact-cas.api-ca",
43+
flagName: "artifact-cas-ca",
44+
},
3745
}
3846

3947
type confOpt struct {

app/cli/cmd/config_view.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ func newConfigViewCmd() *cobra.Command {
2929
Run: func(cmd *cobra.Command, args []string) {
3030
fmt.Printf("Config file: %s\n", viper.ConfigFileUsed())
3131

32-
for _, opt := range []*confOpt{confOptions.controlplaneAPI, confOptions.CASAPI} {
33-
fmt.Printf("%s: %s\n", opt.flagName, viper.GetString(opt.viperKey))
32+
for _, opt := range []*confOpt{confOptions.controlplaneAPI, confOptions.controlplaneCA, confOptions.CASAPI, confOptions.CASCA} {
33+
if v := viper.GetString(opt.viperKey); v != "" {
34+
fmt.Printf("%s: %s\n", opt.flagName, v)
35+
}
3436
}
3537
},
3638
}

app/cli/cmd/root.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,15 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
9292
return err
9393
}
9494

95-
conn, err := grpcconn.New(viper.GetString(confOptions.controlplaneAPI.viperKey), apiToken, flagInsecure)
95+
var opts = []grpcconn.Option{
96+
grpcconn.WithInsecure(flagInsecure),
97+
}
98+
99+
if caFilePath := viper.GetString(confOptions.controlplaneCA.viperKey); caFilePath != "" {
100+
opts = append(opts, grpcconn.WithCAFile(caFilePath))
101+
}
102+
103+
conn, err := grpcconn.New(viper.GetString(confOptions.controlplaneAPI.viperKey), apiToken, opts...)
96104
if err != nil {
97105
return err
98106
}
@@ -136,10 +144,20 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
136144
err := viper.BindPFlag(confOptions.controlplaneAPI.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.controlplaneAPI.flagName))
137145
cobra.CheckErr(err)
138146

147+
// Custom CAs for the control plane
148+
rootCmd.PersistentFlags().String(confOptions.controlplaneCA.flagName, "", "CUSTOM CA file for the Control Plane API (optional)")
149+
err = viper.BindPFlag(confOptions.controlplaneCA.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.controlplaneCA.flagName))
150+
cobra.CheckErr(err)
151+
139152
rootCmd.PersistentFlags().String(confOptions.CASAPI.flagName, defaultCASAPI, "URL for the Artifacts Content Addressable Storage (CAS)")
140153
err = viper.BindPFlag(confOptions.CASAPI.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.CASAPI.flagName))
141154
cobra.CheckErr(err)
142155

156+
// Custom CAs for the CAS
157+
rootCmd.PersistentFlags().String(confOptions.CASCA.flagName, "", "CUSTOM CA file for the Artifacts CAS API (optional)")
158+
err = viper.BindPFlag(confOptions.CASCA.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.CASCA.flagName))
159+
cobra.CheckErr(err)
160+
143161
rootCmd.PersistentFlags().BoolVarP(&flagInsecure, "insecure", "i", false, "Skip TLS transport during connection to the control plane")
144162
rootCmd.PersistentFlags().BoolVar(&flagDebug, "debug", false, "Enable debug/verbose logging mode")
145163
rootCmd.PersistentFlags().StringVarP(&flagOutputFormat, "output", "o", "table", "Output format, valid options are json and table")

app/cli/internal/action/attestation_add.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,18 @@ type AttestationAddOpts struct {
3232
*ActionsOpts
3333
ArtifactsCASConn *grpc.ClientConn
3434
CASURI string
35+
CASCAPath string // optional CA certificate for the CAS connection
3536
ConnectionInsecure bool
3637
// OCI registry credentials used for CONTAINER_IMAGE material type
3738
RegistryServer, RegistryUsername, RegistryPassword string
3839
}
3940

4041
type AttestationAdd struct {
4142
*ActionsOpts
42-
c *crafter.Crafter
43-
casURI string
43+
c *crafter.Crafter
44+
casURI string
45+
// optional CA certificate for the CAS connection
46+
casCAPath string
4447
connectionInsecure bool
4548
}
4649

@@ -60,6 +63,7 @@ func NewAttestationAdd(cfg *AttestationAddOpts) (*AttestationAdd, error) {
6063
ActionsOpts: cfg.ActionsOpts,
6164
c: c,
6265
casURI: cfg.CASURI,
66+
casCAPath: cfg.CASCAPath,
6367
connectionInsecure: cfg.ConnectionInsecure,
6468
}, nil
6569
}
@@ -104,7 +108,15 @@ func (action *AttestationAdd) Run(ctx context.Context, attestationID, materialNa
104108
// Some CASBackends will actually upload information to the CAS server
105109
// in such case we need to set up a connection
106110
if !b.IsInline && creds.Result.Token != "" {
107-
artifactCASConn, err := grpcconn.New(action.casURI, creds.Result.Token, action.connectionInsecure)
111+
var opts = []grpcconn.Option{
112+
grpcconn.WithInsecure(action.connectionInsecure),
113+
}
114+
115+
if action.casCAPath != "" {
116+
opts = append(opts, grpcconn.WithCAFile(action.casCAPath))
117+
}
118+
119+
artifactCASConn, err := grpcconn.New(action.casURI, creds.Result.Token, opts...)
108120
if err != nil {
109121
return err
110122
}

app/controlplane/configs/config.devel.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ server:
1212
addr: 0.0.0.0:9000
1313
# We have some slow operations such as verifying an OCI registry
1414
timeout: 10s
15+
# tls_config:
16+
# certificate: "../../devel/devkeys/selfsigned/controlplane.crt"
17+
# private_key: "../../devel/devkeys/selfsigned/controlplane.key"
1518

1619
certificate_authority:
1720
file_ca:

app/controlplane/pkg/biz/casclient.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func NewCASClientUseCase(credsProvider *CASCredentialsUseCase, config *conf.Boot
6969

7070
// generate a client from the given configuration
7171
defaultCasClientFactory := func(conf *conf.Bootstrap_CASServer, token string) (casclient.DownloaderUploader, func(), error) {
72-
conn, err := grpcconn.New(conf.GetGrpc().GetAddr(), token, conf.GetInsecure())
72+
conn, err := grpcconn.New(conf.GetGrpc().GetAddr(), token, grpcconn.WithInsecure(conf.GetInsecure()))
7373
if err != nil {
7474
return nil, nil, fmt.Errorf("failed to create grpc connection: %w", err)
7575
}

devel/devkeys/selfsigned/cas.crt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEgzCCAmugAwIBAgIUcdwQLV/RVxdC8W4TE957yQf1LqEwDQYJKoZIhvcNAQEL
3+
BQAwSjELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB1NldmlsbGUxGjAYBgNVBAoMEUNo
4+
YWlubG9vcCBSb290IENBMQ0wCwYDVQQLDARjb3JlMB4XDTI0MDYyMzIyMjUzMloX
5+
DTI1MDYyMzIyMjUzMlowRDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYD
6+
VQQKDAtNeU9yZywgSW5jLjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG
7+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdEbOuLzhe1fLPaAAimP9VcCO5b0f9JkYEo+
8+
9AN9XdUbU3DCbAuStTsa83qizzRD9IBYTih3hlFnGH+s3mBJVV4xfqJLqB1DbrZT
9+
Wbr2aqiQeJCwNDx3jtrKrLt1xXd97rE/VvZEU6UsqgBpKM5nJuWd2d4lt5N2jc3q
10+
u222dKCA79SpaaEsorIzK9x4EparWiIZ092oM7Kq0KyNvFac76uiHn3eO+7F6r8i
11+
TQApLBRZM4p0zGGDbr7HVKMjMBim4wc/Epra9dqUeGwxJiJgfmciY7/wpZ2sBIiU
12+
NvwzmTKOzimfu1bSk5GyGXRBPgncnyzjm5j0QI9D/qlgEbC7XQIDAQABo2cwZTAj
13+
BgNVHREEHDAagglsb2NhbGhvc3SCDWFub3RoZXJkb21haW4wHQYDVR0OBBYEFDeM
14+
DkYKHa7chpYqU8e7JFejVTXWMB8GA1UdIwQYMBaAFPT/S8Z/rtqDnPlhNzOM1QN6
15+
iJP5MA0GCSqGSIb3DQEBCwUAA4ICAQCYVzzTWhZTxQdGCIT0EmDvfMVldZi9KOaY
16+
8Ai4IuHrTvQyk1C5K2gPtJucX9UVJVGG200f7kFHdk54YUWR0wEMojxNpURor/Pv
17+
mxGt2hDH4NEMo74F0+coo/3Wb648eCTlWb06/FgYe5oWR6Hg0aWtuB+R559Ry6KT
18+
gP2Ay473MXLljtd3fU1dsvxviB+klVtRBHMQ43jYm2UFGDCE9MIyxUtVxuQGJX0e
19+
FBSB5XgLM6cXe2eEFURkwyQGS0cRLwvrtBkRR0yLOvoCFQ0LZ/AZy2f12gOaZm1I
20+
HGx6YSQfzboTPPbBbLceDxVIox2Vyh9Zy4qij6nqljDdNYOue2/D0TTrDmbzWnih
21+
ode3ux1fNtLLy5oTHId2QSygsT7HeDne2avrDVrhSPb4wn1pd0rDk54hxrT8nz/8
22+
4NKlEUwOkfKGQryW/ZjGBS369Tf872NWR9CV4za7b8plM0uw39YphDnNMpi/SQEa
23+
Ef9RRAPIU8BlsAguceX3HkE+qiciqsTA2NiCLnawa2bIS6sLJ8E5hIB1IZYMctm8
24+
+qBstHaMU3vdq7dmtJWJ0cxI6y4vCEFMzEkGUj617VOeHRvyXsVhtu880Ha7kBJj
25+
pMMnSqVNLJF7RgFNz7GiM7nQ9twZ5J6W4c50IO3alXwgt+ZSTMmL/0qi8sBZfteD
26+
t1dozsM17A==
27+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)