Skip to content

Commit

Permalink
Merge pull request #1031 from arithx/custom_clevis
Browse files Browse the repository at this point in the history
config/internal: add clevis override support
  • Loading branch information
Stephen Lowrie authored Sep 18, 2020
2 parents f05bc76 + 776f321 commit 775433a
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 22 deletions.
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.
* **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

0 comments on commit 775433a

Please sign in to comment.