Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/shared/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ var (
ErrLuksLabelTooLong = errors.New("luks device labels cannot be longer than 47 characters")
ErrLuksNameContainsSlash = errors.New("device names cannot contain slashes")
ErrInvalidLuksKeyFile = errors.New("invalid key-file source")
ErrUnknownClevisPin = errors.New("unsupported clevis pin")
ErrClevisConfigRequired = errors.New("missing required custom clevis config")
ErrClevisCustomWithOthers = errors.New("cannot use custom clevis config with tpm2, tang, or threshold")
ErrTangThumbprintRequired = errors.New("thumbprint is required")
ErrFileIllegalMode = errors.New("illegal file mode")
ErrBothIDAndNameSet = errors.New("cannot set both id and name")
Expand Down
18 changes: 18 additions & 0 deletions config/v3_2_experimental/schema/ignition.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,24 @@
"clevis": {
"type": ["object", "null"],
"properties": {
"custom": {
"type": ["object", "null"],
"properties": {
"pin": {
"type": "string"
},
"config": {
"type": "string"
},
"needsNetwork": {
"type": ["boolean", "null"]
}
},
"required": [
"pin",
"config"
]
},
"tpm2": {
"type": ["boolean", "null"]
},
Expand Down
41 changes: 41 additions & 0 deletions config/v3_2_experimental/types/custom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2020 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package types

import (
"github.com/coreos/ignition/v2/config/shared/errors"

"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
)

func (cu Custom) Key() string {
return cu.Pin
}

func (cu Custom) Validate(c path.ContextPath) (r report.Report) {
if cu.Pin == "" && cu.Config == "" {
return
}
switch cu.Pin {
case "tpm2", "tang", "sss":
default:
r.AddOnError(c.Append("pin"), errors.ErrUnknownClevisPin)
}
if cu.Config == "" {
r.AddOnError(c.Append("config"), errors.ErrClevisConfigRequired)
}
return
}
6 changes: 6 additions & 0 deletions config/v3_2_experimental/types/luks.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ func (l Luks) Validate(c path.ContextPath) (r report.Report) {
r.AddOnError(c.Append("device"), validatePath(*l.Device))
}

if l.Clevis != nil {
if l.Clevis.Custom != nil && (len(l.Clevis.Tang) > 0 || (l.Clevis.Tpm2 != nil && *l.Clevis.Tpm2) || (l.Clevis.Threshold != nil && *l.Clevis.Threshold != 0)) {
r.AddOnError(c.Append("clevis"), errors.ErrClevisCustomWithOthers)
}
}

// fail if a key file is provided and is not valid
if err := validateURLNilOK(l.KeyFile.Source); err != nil {
r.AddOnError(c.Append("keys"), errors.ErrInvalidLuksKeyFile)
Expand Down
13 changes: 10 additions & 3 deletions config/v3_2_experimental/types/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package types
// generated by "schematyper --package=types config/v3_2_experimental/schema/ignition.json -o config/v3_2_experimental/types/schema.go --root-type=Config" -- DO NOT EDIT

type Clevis struct {
Tang []Tang `json:"tang,omitempty"`
Threshold *int `json:"threshold,omitempty"`
Tpm2 *bool `json:"tpm2,omitempty"`
Custom *Custom `json:"custom,omitempty"`
Tang []Tang `json:"tang,omitempty"`
Threshold *int `json:"threshold,omitempty"`
Tpm2 *bool `json:"tpm2,omitempty"`
}

type Config struct {
Expand All @@ -15,6 +16,12 @@ type Config struct {
Systemd Systemd `json:"systemd,omitempty"`
}

type Custom struct {
Config string `json:"config"`
NeedsNetwork *bool `json:"needsNetwork,omitempty"`
Pin string `json:"pin"`
}

type Device string

type Directory struct {
Expand Down
4 changes: 4 additions & 0 deletions docs/configuration-v3_2_experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ The Ignition configuration is a JSON document conforming to the following specif
* **thumbprint** (string): thumbprint of a trusted signing key.
* **_tpm2_** (bool): whether or not to use a tpm2 device.
* **_threshold_** (int): sets the minimum number of pieces required to decrypt the device.
* **_custom_** (object): overrides the clevis configuration. The `pin` & `config` will be passed directly to `clevis luks bind`. If specified, all other clevis options must be omitted.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not new here so we can address this in a follow-up, but WDYT about using the proper noun "Clevis" (capitalized) in descriptions to match upstream?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WFM

* **pin** (string): the clevis pin.
* **config** (string): the clevis configuration JSON.
* **_needsNetwork_** (bool): whether or not the device requires networking.
* **_systemd_** (object): describes the desired state of the systemd units.
* **_units_** (list of objects): the list of systemd units.
* **name** (string): the name of the unit. This must be suffixed with a valid unit type (e.g. "thing.service"). Every unit must have a unique `name`.
Expand Down
50 changes: 32 additions & 18 deletions internal/exec/stages/disks/luks.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,27 +247,41 @@ func (s *stage) createLuks(config types.Config) error {
}

if luks.Clevis != nil {
c := Clevis{
Threshold: 1,
}
if luks.Clevis.Threshold != nil {
c.Threshold = *luks.Clevis.Threshold
}
for _, tang := range luks.Clevis.Tang {
c.Pins.Tang = append(c.Pins.Tang, Tang{
URL: tang.URL,
Thumbprint: *tang.Thumbprint,
})
}
if luks.Clevis.Tpm2 != nil {
c.Pins.Tpm = *luks.Clevis.Tpm2
var pin string
var config string

if luks.Clevis.Custom != nil {
pin = luks.Clevis.Custom.Pin
config = luks.Clevis.Custom.Config
}
clevisJson, err := json.Marshal(c)
if err != nil {
return fmt.Errorf("creating clevis json: %v", err)

// if the override pin is empty the config must also be empty
if pin == "" {
pin = "sss"
c := Clevis{
Threshold: 1,
}
if luks.Clevis.Threshold != nil {
c.Threshold = *luks.Clevis.Threshold
}
for _, tang := range luks.Clevis.Tang {
c.Pins.Tang = append(c.Pins.Tang, Tang{
URL: tang.URL,
Thumbprint: *tang.Thumbprint,
})
}
if luks.Clevis.Tpm2 != nil {
c.Pins.Tpm = *luks.Clevis.Tpm2
}
clevisJson, err := json.Marshal(c)
if err != nil {
return fmt.Errorf("creating clevis json: %v", err)
}
config = string(clevisJson)
}

if _, err := s.Logger.LogCmd(
exec.Command(distro.ClevisCmd(), "luks", "bind", "-f", "-k", keyFilePath, "-d", devAlias, "sss", string(clevisJson)), "Clevis bind",
exec.Command(distro.ClevisCmd(), "luks", "bind", "-f", "-k", keyFilePath, "-d", devAlias, pin, config), "Clevis bind",
); err != nil {
return fmt.Errorf("binding clevis device: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/exec/stages/files/filesystemEntries.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (s *stage) createCrypttabEntries(config types.Config) error {
}
uuid := strings.TrimSpace(string(out))
netdev := ""
if luks.Clevis != nil && len(luks.Clevis.Tang) > 0 {
if luks.Clevis != nil && (len(luks.Clevis.Tang) > 0 || (luks.Clevis.Custom != nil && luks.Clevis.Custom.NeedsNetwork != nil && *luks.Clevis.Custom.NeedsNetwork)) {
netdev = ",_netdev"
}
keyfile := "none"
Expand Down