@@ -2,10 +2,15 @@ package main
2
2
3
3
import (
4
4
"context"
5
+ "crypto/ecdsa"
6
+ "crypto/sha256"
7
+ "crypto/x509"
5
8
"encoding/hex"
6
9
"encoding/json"
10
+ "encoding/pem"
7
11
"fmt"
8
12
"io"
13
+ "log/slog"
9
14
"net"
10
15
"os"
11
16
"time"
@@ -45,6 +50,7 @@ func newSetCmd() *cobra.Command {
45
50
cmd .Flags ().StringP ("coordinator" , "c" , "" , "endpoint the coordinator can be reached at" )
46
51
must (cobra .MarkFlagRequired (cmd .Flags (), "coordinator" ))
47
52
cmd .Flags ().String ("coordinator-policy-hash" , DefaultCoordinatorPolicyHash , "expected policy hash of the coordinator, will not be checked if empty" )
53
+ cmd .Flags ().String ("workload-owner-key" , workloadOwnerPEM , "path to workload owner key (.pem) file" )
48
54
49
55
return cmd
50
56
}
@@ -69,6 +75,11 @@ func runSet(cmd *cobra.Command, args []string) error {
69
75
return fmt .Errorf ("failed to unmarshal manifest: %w" , err )
70
76
}
71
77
78
+ workloadOwnerKey , err := loadWorkloadOwnerKey (flags .workloadOwnerKeyPath , m , log )
79
+ if err != nil {
80
+ return fmt .Errorf ("loading workload owner key: %w" , err )
81
+ }
82
+
72
83
paths , err := findGenerateTargets (args , log )
73
84
if err != nil {
74
85
return fmt .Errorf ("finding yaml files: %w" , err )
@@ -92,7 +103,7 @@ func runSet(cmd *cobra.Command, args []string) error {
92
103
kdsCache := fsstore .New (kdsDir , log .WithGroup ("kds-cache" ))
93
104
kdsGetter := snp .NewCachedHTTPSGetter (kdsCache , snp .NeverGCTicker , log .WithGroup ("kds-getter" ))
94
105
validator := snp .NewValidator (validateOptsGen , kdsGetter , log .WithGroup ("snp-validator" ))
95
- dialer := dialer .New (atls .NoIssuer , validator , & net.Dialer {})
106
+ dialer := dialer .NewWithKey (atls .NoIssuer , validator , & net.Dialer {}, workloadOwnerKey )
96
107
97
108
conn , err := dialer .Dial (cmd .Context (), flags .coordinator )
98
109
if err != nil {
@@ -124,9 +135,10 @@ func runSet(cmd *cobra.Command, args []string) error {
124
135
}
125
136
126
137
type setFlags struct {
127
- manifestPath string
128
- coordinator string
129
- policy []byte
138
+ manifestPath string
139
+ coordinator string
140
+ policy []byte
141
+ workloadOwnerKeyPath string
130
142
}
131
143
132
144
func parseSetFlags (cmd * cobra.Command ) (* setFlags , error ) {
@@ -149,6 +161,10 @@ func parseSetFlags(cmd *cobra.Command) (*setFlags, error) {
149
161
if err != nil {
150
162
return nil , fmt .Errorf ("hex-decoding coordinator-policy-hash flag: %w" , err )
151
163
}
164
+ flags .workloadOwnerKeyPath , err = cmd .Flags ().GetString ("workload-owner-key" )
165
+ if err != nil {
166
+ return nil , fmt .Errorf ("getting workload-owner-key flag: %w" , err )
167
+ }
152
168
153
169
return flags , nil
154
170
}
@@ -161,6 +177,54 @@ func policyMapToBytesList(m map[string]deployment) [][]byte {
161
177
return policies
162
178
}
163
179
180
+ func loadWorkloadOwnerKey (path string , manifst manifest.Manifest , log * slog.Logger ) (* ecdsa.PrivateKey , error ) {
181
+ key , err := os .ReadFile (path )
182
+ if os .IsNotExist (err ) {
183
+ if len (manifst .WorkloadOwnerKeys ) == 0 {
184
+ log .Warn ("No workload owner keys in manifest nor private key found. Further manifest updates will be rejected by the coordinator." )
185
+ } else {
186
+ log .Warn ("No workload owner private key found. Setting the manifest may fail." )
187
+ }
188
+ return nil , nil
189
+ }
190
+ if err != nil {
191
+ return nil , fmt .Errorf ("reading workload owner key: %w" , err )
192
+ }
193
+ pemBlock , _ := pem .Decode (key )
194
+ if pemBlock == nil {
195
+ return nil , fmt .Errorf ("decoding workload owner key: %w" , err )
196
+ }
197
+ if pemBlock .Type != "EC PRIVATE KEY" {
198
+ return nil , fmt .Errorf ("workload owner key is not an EC private key" )
199
+ }
200
+ workloadOwnerKey , err := x509 .ParseECPrivateKey (pemBlock .Bytes )
201
+ if err != nil {
202
+ return nil , fmt .Errorf ("parsing workload owner key: %w" , err )
203
+ }
204
+ pubKey , err := x509 .MarshalPKIXPublicKey (& workloadOwnerKey .PublicKey )
205
+ if err != nil {
206
+ return nil , fmt .Errorf ("marshaling public key: %w" , err )
207
+ }
208
+ ownerKeyHash := sha256 .Sum256 (pubKey )
209
+ ownerKeyHex := manifest .NewHexString (ownerKeyHash [:])
210
+ if len (manifst .WorkloadOwnerKeys ) == 0 {
211
+ log .Warn ("No workload owner keys in manifest. Further manifest updates will be rejected by the coordinator" )
212
+ return workloadOwnerKey , nil
213
+ }
214
+ log .Debug ("Workload owner keys in manifest" , "keys" , manifst .WorkloadOwnerKeys )
215
+ var found bool
216
+ for _ , k := range manifst .WorkloadOwnerKeys {
217
+ if k == ownerKeyHex {
218
+ found = true
219
+ break
220
+ }
221
+ }
222
+ if ! found {
223
+ log .Warn ("Workload owner key not found in manifest. This may lock you out from further updates" )
224
+ }
225
+ return workloadOwnerKey , nil
226
+ }
227
+
164
228
func setLoop (
165
229
ctx context.Context , client coordapi.CoordAPIClient , out io.Writer , req * coordapi.SetManifestRequest ,
166
230
) (resp * coordapi.SetManifestResponse , retErr error ) {
0 commit comments