Skip to content

Commit 97024fb

Browse files
committed
add trusted ca certificate support
Signed-off-by: Nick Petrovic <[email protected]>
1 parent 8eccbeb commit 97024fb

File tree

7 files changed

+149
-0
lines changed

7 files changed

+149
-0
lines changed

examples/default.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,27 @@ ssh:
103103
# ADVANCED CONFIGURATION
104104
# ===================================================================== #
105105

106+
caCerts:
107+
# If set to `true`, this will remove all the default trusted CA certificates that
108+
# are normally shipped with the OS.
109+
# 🟢 Builtin default: false
110+
removeDefaults: null
111+
112+
# A list of trusted CA certificate files. The files will be read and passed to cloud-init.
113+
files:
114+
# - examples/hello.crt
115+
116+
# A list of trusted CA certificates. These are directly passed to cloud-init.
117+
certs:
118+
# - |
119+
# -----BEGIN CERTIFICATE-----
120+
# YOUR-ORGS-TRUSTED-CA-CERT-HERE
121+
# -----END CERTIFICATE-----
122+
# - |
123+
# -----BEGIN CERTIFICATE-----
124+
# YOUR-ORGS-TRUSTED-CA-CERT-HERE
125+
# -----END CERTIFICATE-----
126+
106127
containerd:
107128
# Enable system-wide (aka rootful) containerd and its dependencies (BuildKit, Stargz Snapshotter)
108129
# 🟢 Builtin default: false

pkg/cidata/cidata.TEMPLATE.d/user-data

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,15 @@ resolv_conf:
5252
- {{$ns}}
5353
{{- end }}
5454
{{- end }}
55+
56+
{{ with .CACerts }}
57+
ca-certs:
58+
remove_defaults: {{ .RemoveDefaults }}
59+
trusted:
60+
{{- range $cert := .Trusted }}
61+
- |
62+
{{- range $line := $cert.Lines }}
63+
{{ $line }}
64+
{{- end }}
65+
{{- end }}
66+
{{- end }}

pkg/cidata/cidata.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,28 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort
186186
}
187187
}
188188

189+
args.CACerts.RemoveDefaults = y.CACertificates.RemoveDefaults
190+
191+
for _, path := range y.CACertificates.Files {
192+
expanded, err := localpathutil.Expand(path)
193+
if err != nil {
194+
return err
195+
}
196+
197+
content, err := os.ReadFile(expanded)
198+
if err != nil {
199+
return err
200+
}
201+
202+
cert := getCert(string(content))
203+
args.CACerts.Trusted = append(args.CACerts.Trusted, cert)
204+
}
205+
206+
for _, content := range y.CACertificates.Certs {
207+
cert := getCert(content)
208+
args.CACerts.Trusted = append(args.CACerts.Trusted, cert)
209+
}
210+
189211
if err := ValidateTemplateArgs(args); err != nil {
190212
return err
191213
}
@@ -244,3 +266,15 @@ func GuestAgentBinary(arch string) (io.ReadCloser, error) {
244266
gaPath := filepath.Join(dir, "lima-guestagent.Linux-"+arch)
245267
return os.Open(gaPath)
246268
}
269+
270+
func getCert(content string) Cert {
271+
lines := []string{}
272+
for _, line := range strings.Split(content, "\n") {
273+
if line == "" {
274+
continue
275+
}
276+
lines = append(lines, strings.TrimSpace(line))
277+
}
278+
// return lines
279+
return Cert{Lines: lines}
280+
}

pkg/cidata/template.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ var templateFS embed.FS
1919

2020
const templateFSRoot = "cidata.TEMPLATE.d"
2121

22+
type CACerts struct {
23+
RemoveDefaults *bool
24+
Trusted []Cert
25+
}
26+
27+
type Cert struct {
28+
Lines []string
29+
}
30+
2231
type Containerd struct {
2332
System bool
2433
User bool
@@ -51,6 +60,7 @@ type TemplateArgs struct {
5160
TCPDNSLocalPort int
5261
Env map[string]string
5362
DNSAddresses []string
63+
CACerts CACerts
5464
}
5565

5666
func ValidateTemplateArgs(args TemplateArgs) error {

pkg/limayaml/defaults.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ func MACAddress(uniqueID string) string {
7272
// - Mounts are appended in d, y, o order, but "merged" when the Location matches a previous entry;
7373
// the highest priority Writable setting wins.
7474
// - DNS are picked from the highest priority where DNS is not empty.
75+
// - CACertificates Files and Certs are uniquely appended
7576
func FillDefault(y, d, o *LimaYAML, filePath string) {
7677
if y.Arch == nil {
7778
y.Arch = d.Arch
@@ -450,6 +451,22 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
450451
env[k] = v
451452
}
452453
y.Env = env
454+
455+
if y.CACertificates.RemoveDefaults == nil {
456+
y.CACertificates.RemoveDefaults = d.CACertificates.RemoveDefaults
457+
}
458+
if o.CACertificates.RemoveDefaults != nil {
459+
y.CACertificates.RemoveDefaults = o.CACertificates.RemoveDefaults
460+
}
461+
if y.CACertificates.RemoveDefaults == nil {
462+
y.CACertificates.RemoveDefaults = pointer.Bool(false)
463+
}
464+
465+
caFiles := unique(append(append(d.CACertificates.Files, y.CACertificates.Files...), o.CACertificates.Files...))
466+
y.CACertificates.Files = caFiles
467+
468+
caCerts := unique(append(append(d.CACertificates.Certs, y.CACertificates.Certs...), o.CACertificates.Certs...))
469+
y.CACertificates.Certs = caCerts
453470
}
454471

455472
func FillPortForwardDefaults(rule *PortForward, instDir string) {
@@ -561,3 +578,15 @@ func Cname(host string) string {
561578
}
562579
return host
563580
}
581+
582+
func unique(s []string) []string {
583+
keys := make(map[string]bool)
584+
list := []string{}
585+
for _, entry := range s {
586+
if _, found := keys[entry]; !found {
587+
keys[entry] = true
588+
list = append(list, entry)
589+
}
590+
}
591+
return list
592+
}

pkg/limayaml/defaults_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ func TestFillDefault(t *testing.T) {
7676
IPv6: pointer.Bool(false),
7777
},
7878
PropagateProxyEnv: pointer.Bool(true),
79+
CACertificates: CACertificates{
80+
RemoveDefaults: pointer.Bool(false),
81+
},
7982
}
8083
builtin.CPUType[arch] = "host"
8184

@@ -126,6 +129,12 @@ func TestFillDefault(t *testing.T) {
126129
Env: map[string]string{
127130
"ONE": "Eins",
128131
},
132+
CACertificates: CACertificates{
133+
Files: []string{"ca.crt"},
134+
Certs: []string{
135+
"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
136+
},
137+
},
129138
}
130139

131140
expect := builtin
@@ -179,6 +188,14 @@ func TestFillDefault(t *testing.T) {
179188

180189
expect.Env = y.Env
181190

191+
expect.CACertificates = CACertificates{
192+
RemoveDefaults: pointer.Bool(false),
193+
Files: []string{"ca.crt"},
194+
Certs: []string{
195+
"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
196+
},
197+
}
198+
182199
FillDefault(&y, &LimaYAML{}, &LimaYAML{}, filePath)
183200
assert.DeepEqual(t, &y, &expect, opts...)
184201

@@ -267,6 +284,12 @@ func TestFillDefault(t *testing.T) {
267284
"ONE": "one",
268285
"TWO": "two",
269286
},
287+
CACertificates: CACertificates{
288+
RemoveDefaults: pointer.Bool(true),
289+
Certs: []string{
290+
"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
291+
},
292+
},
270293
}
271294

272295
expect = d
@@ -282,6 +305,10 @@ func TestFillDefault(t *testing.T) {
282305
"default.": d.HostResolver.Hosts["default"],
283306
}
284307
expect.MountType = pointer.String(REVSSHFS)
308+
expect.CACertificates.RemoveDefaults = pointer.Bool(true)
309+
expect.CACertificates.Certs = []string{
310+
"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
311+
}
285312

286313
y = LimaYAML{}
287314
FillDefault(&y, &d, &LimaYAML{}, filePath)
@@ -413,6 +440,9 @@ func TestFillDefault(t *testing.T) {
413440
"TWO": "deux",
414441
"THREE": "trois",
415442
},
443+
CACertificates: CACertificates{
444+
RemoveDefaults: pointer.Bool(true),
445+
},
416446
}
417447

418448
y = filledDefaults
@@ -451,6 +481,12 @@ func TestFillDefault(t *testing.T) {
451481
// ONE remains from filledDefaults.Env; the rest are set from o
452482
expect.Env["ONE"] = y.Env["ONE"]
453483

484+
expect.CACertificates.RemoveDefaults = pointer.Bool(true)
485+
expect.CACertificates.Files = []string{"ca.crt"}
486+
expect.CACertificates.Certs = []string{
487+
"-----BEGIN CERTIFICATE-----\nYOUR-ORGS-TRUSTED-CA-CERT\n-----END CERTIFICATE-----\n",
488+
}
489+
454490
FillDefault(&y, &d, &o, filePath)
455491
assert.DeepEqual(t, &y, &expect, opts...)
456492
}

pkg/limayaml/limayaml.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type LimaYAML struct {
3030
HostResolver HostResolver `yaml:"hostResolver,omitempty" json:"hostResolver,omitempty"`
3131
UseHostResolver *bool `yaml:"useHostResolver,omitempty" json:"useHostResolver,omitempty"` // DEPRECATED, use `HostResolver.Enabled` instead
3232
PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"`
33+
CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"`
3334
}
3435

3536
type Arch = string
@@ -155,6 +156,12 @@ type HostResolver struct {
155156
Hosts map[string]string `yaml:"hosts,omitempty" json:"hosts,omitempty"`
156157
}
157158

159+
type CACertificates struct {
160+
RemoveDefaults *bool `yaml:"removeDefaults,omitempty" json:"removeDefaults,omitempty"` // default: false
161+
Files []string `yaml:"files,omitempty" json:"files,omitempty"`
162+
Certs []string `yaml:"certs,omitempty" json:"certs,omitempty"`
163+
}
164+
158165
// DEPRECATED types below
159166

160167
// Types have been renamed to turn all references to the old names into compiler errors,

0 commit comments

Comments
 (0)