diff --git a/channels/pkg/channels/addon.go b/channels/pkg/channels/addon.go index a72e0b7184..16493be58f 100644 --- a/channels/pkg/channels/addon.go +++ b/channels/pkg/channels/addon.go @@ -273,7 +273,7 @@ func (a *Addon) installPKI(ctx context.Context, k8sClient kubernetes.Interface, a.Name, }, } - cert, privateKey, _, err := pki.IssueCert(req, nil) + cert, privateKey, _, err := pki.IssueCert(ctx, req, nil) if err != nil { return err } diff --git a/cmd/kops-controller/pkg/server/keystore.go b/cmd/kops-controller/pkg/server/keystore.go index c2feb48ac5..77886f64af 100644 --- a/cmd/kops-controller/pkg/server/keystore.go +++ b/cmd/kops-controller/pkg/server/keystore.go @@ -17,6 +17,7 @@ limitations under the License. package server import ( + "context" "fmt" "os" "path" @@ -36,7 +37,8 @@ type keystoreEntry struct { var _ pki.Keystore = keystore{} -func (k keystore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error) { +// FindPrimaryKeypair implements pki.Keystore +func (k keystore) FindPrimaryKeypair(ctx context.Context, name string) (*pki.Certificate, *pki.PrivateKey, error) { entry, ok := k.keys[name] if !ok { return nil, nil, fmt.Errorf("unknown CA %q", name) diff --git a/cmd/kops-controller/pkg/server/server.go b/cmd/kops-controller/pkg/server/server.go index b029cf2c54..80a17e4855 100644 --- a/cmd/kops-controller/pkg/server/server.go +++ b/cmd/kops-controller/pkg/server/server.go @@ -180,7 +180,7 @@ func (s *Server) bootstrap(w http.ResponseWriter, r *http.Request) { validHours := (455 * 24) + (hash.Sum32() % (30 * 24)) for name, pubKey := range req.Certs { - cert, err := s.issueCert(name, pubKey, id, validHours, req.KeypairIDs) + cert, err := s.issueCert(ctx, name, pubKey, id, validHours, req.KeypairIDs) if err != nil { klog.Infof("bootstrap %s cert %q issue err: %v", r.RemoteAddr, name, err) w.WriteHeader(http.StatusBadRequest) @@ -195,7 +195,7 @@ func (s *Server) bootstrap(w http.ResponseWriter, r *http.Request) { klog.Infof("bootstrap %s %s success", r.RemoteAddr, id.NodeName) } -func (s *Server) issueCert(name string, pubKey string, id *bootstrap.VerifyResult, validHours uint32, keypairIDs map[string]string) (string, error) { +func (s *Server) issueCert(ctx context.Context, name string, pubKey string, id *bootstrap.VerifyResult, validHours uint32, keypairIDs map[string]string) (string, error) { block, _ := pem.Decode([]byte(pubKey)) if block.Type != "RSA PUBLIC KEY" { return "", fmt.Errorf("unexpected key type %q", block.Type) @@ -251,7 +251,7 @@ func (s *Server) issueCert(name string, pubKey string, id *bootstrap.VerifyResul } } - cert, _, _, err := pki.IssueCert(issueReq, s.keystore) + cert, _, _, err := pki.IssueCert(ctx, issueReq, s.keystore) if err != nil { return "", fmt.Errorf("issuing certificate: %v", err) } diff --git a/cmd/kops/create_keypair.go b/cmd/kops/create_keypair.go index d8a0e90c2a..bfac1f1d22 100644 --- a/cmd/kops/create_keypair.go +++ b/cmd/kops/create_keypair.go @@ -215,7 +215,7 @@ func createKeypair(ctx context.Context, out io.Writer, options *CreateKeypairOpt Serial: serial, PrivateKey: privateKey, } - cert, _, _, err = pki.IssueCert(&req, nil) + cert, _, _, err = pki.IssueCert(ctx, &req, nil) if err != nil { return fmt.Errorf("error issuing certificate: %v", err) } @@ -232,7 +232,7 @@ func createKeypair(ctx context.Context, out io.Writer, options *CreateKeypairOpt } } - keyset, err := keyStore.FindKeyset(name) + keyset, err := keyStore.FindKeyset(ctx, name) var item *fi.KeysetItem if os.IsNotExist(err) || (err == nil && keyset == nil) { if options.Primary { @@ -295,12 +295,14 @@ func completeKeyset(ctx context.Context, cluster *kopsapi.Cluster, clientSet sim return nil, nil, keysets, cobra.ShellCompDirectiveNoFileComp } - keyset, err = keyStore.FindKeyset(args[0]) + keyset, err = keyStore.FindKeyset(ctx, args[0]) if err != nil { completions, directive := commandutils.CompletionError("finding keyset", err) return nil, keyStore, completions, directive } + // keyset may be nil if not found + return keyset, keyStore, nil, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/kops/distrust_keypair.go b/cmd/kops/distrust_keypair.go index 6a48936c16..dec285bb1d 100644 --- a/cmd/kops/distrust_keypair.go +++ b/cmd/kops/distrust_keypair.go @@ -145,7 +145,7 @@ func RunDistrustKeypair(ctx context.Context, f *util.Factory, out io.Writer, opt } func distrustKeypair(ctx context.Context, out io.Writer, name string, keypairIDs []string, keyStore fi.CAStore) error { - keyset, err := keyStore.FindKeyset(name) + keyset, err := keyStore.FindKeyset(ctx, name) if err != nil { return err } else if keyset == nil { diff --git a/cmd/kops/export_kubeconfig.go b/cmd/kops/export_kubeconfig.go index 00095624f9..da2b95ef3d 100644 --- a/cmd/kops/export_kubeconfig.go +++ b/cmd/kops/export_kubeconfig.go @@ -145,6 +145,7 @@ func RunExportKubeconfig(ctx context.Context, f *util.Factory, out io.Writer, op return err } conf, err := kubeconfig.BuildKubecfg( + ctx, cluster, keyStore, secretStore, diff --git a/cmd/kops/promote_keypair.go b/cmd/kops/promote_keypair.go index 7b41a7669d..d7595239f7 100644 --- a/cmd/kops/promote_keypair.go +++ b/cmd/kops/promote_keypair.go @@ -154,7 +154,7 @@ func RunPromoteKeypair(ctx context.Context, f *util.Factory, out io.Writer, opti } func promoteKeypair(ctx context.Context, out io.Writer, name string, keypairID string, keyStore fi.CAStore) error { - keyset, err := keyStore.FindKeyset(name) + keyset, err := keyStore.FindKeyset(ctx, name) if err != nil { return fmt.Errorf("reading keyset: %v", err) } else if keyset == nil { diff --git a/cmd/kops/trust_keypair.go b/cmd/kops/trust_keypair.go index 237f822e54..e6757a52c9 100644 --- a/cmd/kops/trust_keypair.go +++ b/cmd/kops/trust_keypair.go @@ -108,10 +108,13 @@ func RunTrustKeypair(ctx context.Context, f *util.Factory, out io.Writer, option return err } - keyset, err := keyStore.FindKeyset(options.Keyset) + keyset, err := keyStore.FindKeyset(ctx, options.Keyset) if err != nil { return err } + if keyset == nil { + return fmt.Errorf("keyset %q not found", options.Keyset) + } for _, id := range options.KeypairIDs { item := keyset.Items[id] diff --git a/cmd/kops/update_cluster.go b/cmd/kops/update_cluster.go index eed80cbb27..6f4f1cd074 100644 --- a/cmd/kops/update_cluster.go +++ b/cmd/kops/update_cluster.go @@ -325,6 +325,7 @@ func RunUpdateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Up // TODO: Another flag? useKopsAuthenticationPlugin := false conf, err := kubeconfig.BuildKubecfg( + ctx, cluster, keyStore, secretStore, diff --git a/nodeup/pkg/model/context.go b/nodeup/pkg/model/context.go index 92a0ec0887..2f5d975ad9 100644 --- a/nodeup/pkg/model/context.go +++ b/nodeup/pkg/model/context.go @@ -289,9 +289,12 @@ func (c *NodeupModelContext) BuildBootstrapKubeconfig(name string, ctx *fi.Nodeu return kubeConfig.GetConfig(), nil } else { - keyset, err := c.KeyStore.FindKeyset(name) + keyset, err := c.KeyStore.FindKeyset(ctx.Context(), name) if err != nil { - return nil, fmt.Errorf("error fetching keyset: %v from keystore: %v", name, err) + return nil, fmt.Errorf("error fetching keyset %q from keystore: %w", name, err) + } + if keyset == nil { + return nil, fmt.Errorf("keyset %q not found", name) } keypairID := c.NodeupConfig.KeypairIDs[name] @@ -422,10 +425,13 @@ func (c *NodeupModelContext) buildCertificatePairTask(ctx *fi.NodeupModelBuilder return fmt.Errorf("no keypair ID for %q", name) } - keyset, err := c.KeyStore.FindKeyset(name) + keyset, err := c.KeyStore.FindKeyset(ctx.Context(), name) if err != nil { return err } + if keyset == nil { + return fmt.Errorf("keyset %q not found", name) + } item := keyset.Items[keypairID] if item == nil { @@ -476,7 +482,7 @@ func (c *NodeupModelContext) buildCertificatePairTask(ctx *fi.NodeupModelBuilder // BuildCertificateTask builds a task to create a certificate file. func (c *NodeupModelContext) BuildCertificateTask(ctx *fi.NodeupModelBuilderContext, name, filename string, owner *string) error { - keyset, err := c.KeyStore.FindKeyset(name) + keyset, err := c.KeyStore.FindKeyset(ctx.Context(), name) if err != nil { return err } @@ -507,7 +513,7 @@ func (c *NodeupModelContext) BuildCertificateTask(ctx *fi.NodeupModelBuilderCont // BuildLegacyPrivateKeyTask builds a task to create a private key file. func (c *NodeupModelContext) BuildLegacyPrivateKeyTask(ctx *fi.NodeupModelBuilderContext, name, filename string, owner *string) error { - keyset, err := c.KeyStore.FindKeyset(name) + keyset, err := c.KeyStore.FindKeyset(ctx.Context(), name) if err != nil { return err } diff --git a/nodeup/pkg/model/fakes_test.go b/nodeup/pkg/model/fakes_test.go index a861c3fb95..ba8be08286 100644 --- a/nodeup/pkg/model/fakes_test.go +++ b/nodeup/pkg/model/fakes_test.go @@ -36,8 +36,9 @@ type fakeKeystore struct { var _ fi.Keystore = &fakeKeystore{} -func (k fakeKeystore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error) { - keyset, err := k.FindKeyset(name) +// FindPrimaryKeypair implements pki.Keystore +func (k fakeKeystore) FindPrimaryKeypair(ctx context.Context, name string) (*pki.Certificate, *pki.PrivateKey, error) { + keyset, err := k.FindKeyset(ctx, name) if err != nil { return nil, nil, err } @@ -45,7 +46,8 @@ func (k fakeKeystore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.Pr return keyset.Primary.Certificate, keyset.Primary.PrivateKey, nil } -func (k fakeKeystore) FindKeyset(name string) (*fi.Keyset, error) { +// FindKeyset implements KeystoreReader. +func (k fakeKeystore) FindKeyset(ctx context.Context, name string) (*fi.Keyset, error) { kopsKeyset := k.privateKeysets[name] if kopsKeyset == nil { return nil, nil diff --git a/pkg/commands/helpers/kubectl_auth.go b/pkg/commands/helpers/kubectl_auth.go index ab983348f2..24c2a20ade 100644 --- a/pkg/commands/helpers/kubectl_auth.go +++ b/pkg/commands/helpers/kubectl_auth.go @@ -255,7 +255,7 @@ func buildCredentials(ctx context.Context, f *util.Factory, options *HelperKubec }, Validity: options.Lifetime, } - cert, privateKey, _, err := pki.IssueCert(&req, keyStore) + cert, privateKey, _, err := pki.IssueCert(ctx, &req, keyStore) if err != nil { return nil, fmt.Errorf("unable to issue certificate: %v", err) } diff --git a/pkg/configserver/keystore.go b/pkg/configserver/keystore.go index 65626a31ea..27868160de 100644 --- a/pkg/configserver/keystore.go +++ b/pkg/configserver/keystore.go @@ -17,6 +17,7 @@ limitations under the License. package configserver import ( + "context" "fmt" "k8s.io/kops/pkg/pki" @@ -31,11 +32,11 @@ func NewKeyStore() fi.KeystoreReader { } // FindPrimaryKeypair implements pki.Keystore -func (s *configserverKeyStore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error) { +func (s *configserverKeyStore) FindPrimaryKeypair(ctx context.Context, name string) (*pki.Certificate, *pki.PrivateKey, error) { return nil, nil, fmt.Errorf("FindPrimaryKeypair %q not supported by configserverKeyStore", name) } -// FindKeyset implements fi.Keystore -func (s *configserverKeyStore) FindKeyset(name string) (*fi.Keyset, error) { +// FindKeyset implements KeystoreReader. +func (s *configserverKeyStore) FindKeyset(ctx context.Context, name string) (*fi.Keyset, error) { return nil, fmt.Errorf("FindKeyset %q not supported by configserverKeyStore", name) } diff --git a/pkg/kubeconfig/create_kubecfg.go b/pkg/kubeconfig/create_kubecfg.go index 584815c2e8..c3def497fa 100644 --- a/pkg/kubeconfig/create_kubecfg.go +++ b/pkg/kubeconfig/create_kubecfg.go @@ -17,6 +17,7 @@ limitations under the License. package kubeconfig import ( + "context" "crypto/x509/pkix" "fmt" "os/user" @@ -32,7 +33,7 @@ import ( const DefaultKubecfgAdminLifetime = 18 * time.Hour -func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, cloud fi.Cloud, admin time.Duration, configUser string, internal bool, kopsStateStore string, useKopsAuthenticationPlugin bool) (*KubeconfigBuilder, error) { +func BuildKubecfg(ctx context.Context, cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.SecretStore, cloud fi.Cloud, admin time.Duration, configUser string, internal bool, kopsStateStore string, useKopsAuthenticationPlugin bool) (*KubeconfigBuilder, error) { clusterName := cluster.ObjectMeta.Name var server string @@ -88,7 +89,7 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se // add the CA Cert to the kubeconfig only if we didn't specify a certificate for the LB // or if we're using admin credentials and the secondary port if cluster.Spec.API.LoadBalancer == nil || cluster.Spec.API.LoadBalancer.SSLCertificate == "" || cluster.Spec.API.LoadBalancer.Class == kops.LoadBalancerClassNetwork || internal { - keySet, err := keyStore.FindKeyset(fi.CertificateIDCA) + keySet, err := keyStore.FindKeyset(ctx, fi.CertificateIDCA) if err != nil { return nil, fmt.Errorf("error fetching CA keypair: %v", err) } @@ -120,7 +121,7 @@ func BuildKubecfg(cluster *kops.Cluster, keyStore fi.Keystore, secretStore fi.Se }, Validity: admin, } - cert, privateKey, _, err := pki.IssueCert(&req, keyStore) + cert, privateKey, _, err := pki.IssueCert(ctx, &req, keyStore) if err != nil { return nil, err } diff --git a/pkg/kubeconfig/create_kubecfg_test.go b/pkg/kubeconfig/create_kubecfg_test.go index 691464b154..34dad01804 100644 --- a/pkg/kubeconfig/create_kubecfg_test.go +++ b/pkg/kubeconfig/create_kubecfg_test.go @@ -101,11 +101,15 @@ type fakeKeyStore struct { MirrorToFn func(basedir vfs.Path) error } -func (f fakeKeyStore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error) { - return fi.FindPrimaryKeypair(f, name) +var _ fi.Keystore = &fakeKeyStore{} + +// FindPrimaryKeypair implements pki.Keystore +func (f fakeKeyStore) FindPrimaryKeypair(ctx context.Context, name string) (*pki.Certificate, *pki.PrivateKey, error) { + return fi.FindPrimaryKeypair(ctx, f, name) } -func (f fakeKeyStore) FindKeyset(name string) (*fi.Keyset, error) { +// FindKeyset implements KeystoreReader. +func (f fakeKeyStore) FindKeyset(ctx context.Context, name string) (*fi.Keyset, error) { return f.FindKeysetFn(name) } @@ -349,6 +353,8 @@ func TestBuildKubecfg(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + ctx := context.TODO() + kopsStateStore := "memfs://example-state-store" keyStore := fakeKeyStore{ @@ -358,7 +364,7 @@ func TestBuildKubecfg(t *testing.T) { }, } - got, err := BuildKubecfg(tt.args.cluster, keyStore, tt.args.secretStore, tt.args.status, tt.args.admin, tt.args.user, tt.args.internal, kopsStateStore, tt.args.useKopsAuthenticationPlugin) + got, err := BuildKubecfg(ctx, tt.args.cluster, keyStore, tt.args.secretStore, tt.args.status, tt.args.admin, tt.args.user, tt.args.internal, kopsStateStore, tt.args.useKopsAuthenticationPlugin) if (err != nil) != tt.wantErr { t.Errorf("BuildKubecfg() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/pki/issue.go b/pkg/pki/issue.go index df83d568e3..565dc5d80c 100644 --- a/pkg/pki/issue.go +++ b/pkg/pki/issue.go @@ -17,6 +17,7 @@ limitations under the License. package pki import ( + "context" "crypto" "crypto/x509" "crypto/x509/pkix" @@ -58,11 +59,12 @@ type IssueCertRequest struct { type Keystore interface { // FindPrimaryKeypair finds a cert & private key, returning nil where either is not found // (if the certificate is found but not keypair, that is not an error: only the cert will be returned). - FindPrimaryKeypair(name string) (*Certificate, *PrivateKey, error) + // Also note that if the keypair is not found at all, this returns (nil, nil, nil) + FindPrimaryKeypair(ctx context.Context, name string) (*Certificate, *PrivateKey, error) } // IssueCert issues a certificate, either a self-signed CA or from a CA in a keystore. -func IssueCert(request *IssueCertRequest, keystore Keystore) (issuedCertificate *Certificate, issuedKey *PrivateKey, caCertificate *Certificate, err error) { +func IssueCert(ctx context.Context, request *IssueCertRequest, keystore Keystore) (issuedCertificate *Certificate, issuedKey *PrivateKey, caCertificate *Certificate, err error) { certificateType := request.Type if expanded, found := wellKnownCertificateTypes[certificateType]; found { certificateType = expanded @@ -116,7 +118,7 @@ func IssueCert(request *IssueCertRequest, keystore Keystore) (issuedCertificate var signer *x509.Certificate if !template.IsCA { var err error - caCertificate, caPrivateKey, err = keystore.FindPrimaryKeypair(request.Signer) + caCertificate, caPrivateKey, err = keystore.FindPrimaryKeypair(ctx, request.Signer) if err != nil { return nil, nil, nil, err } diff --git a/pkg/pki/issue_test.go b/pkg/pki/issue_test.go index ec6d48473e..3fbd8d7408 100644 --- a/pkg/pki/issue_test.go +++ b/pkg/pki/issue_test.go @@ -17,6 +17,7 @@ limitations under the License. package pki import ( + "context" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" @@ -38,7 +39,8 @@ type mockKeystore struct { invoked bool } -func (m *mockKeystore) FindPrimaryKeypair(name string) (*Certificate, *PrivateKey, error) { +// FindPrimaryKeypair implements pki.Keystore +func (m *mockKeystore) FindPrimaryKeypair(ctx context.Context, name string) (*Certificate, *PrivateKey, error) { assert.False(m.t, m.invoked, "invoked already") m.invoked = true assert.Equal(m.t, m.signer, name, "name argument") @@ -139,6 +141,8 @@ func TestIssueCert(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { + ctx := context.TODO() + var minExpectedValidity int64 if tc.req.Validity == 0 { minExpectedValidity = time.Now().Add(time.Hour * 10 * 365 * 24).Unix() @@ -156,7 +160,7 @@ func TestIssueCert(t *testing.T) { key: caPrivateKey, } } - certificate, key, caCert, err := IssueCert(&tc.req, keystore) + certificate, key, caCert, err := IssueCert(ctx, &tc.req, keystore) require.NoError(t, err) cert := certificate.Certificate diff --git a/upup/pkg/fi/ca.go b/upup/pkg/fi/ca.go index 43d65a40c5..cbcf45a84d 100644 --- a/upup/pkg/fi/ca.go +++ b/upup/pkg/fi/ca.go @@ -71,8 +71,8 @@ type KeysetItem struct { type KeystoreReader interface { pki.Keystore - // FindKeyset finds a Keyset. - FindKeyset(name string) (*Keyset, error) + // FindKeyset finds a Keyset. If the keyset is not found, it returns (nil, nil) + FindKeyset(ctx context.Context, name string) (*Keyset, error) } // Keystore contains just the functions we need to issue keypairs, not to list / manage them @@ -112,8 +112,8 @@ type SSHCredentialStore interface { } // FindPrimaryKeypair is a common implementation of pki.FindPrimaryKeypair. -func FindPrimaryKeypair(c Keystore, name string) (*pki.Certificate, *pki.PrivateKey, error) { - keyset, err := c.FindKeyset(name) +func FindPrimaryKeypair(ctx context.Context, c Keystore, name string) (*pki.Certificate, *pki.PrivateKey, error) { + keyset, err := c.FindKeyset(ctx, name) if err != nil { return nil, nil, err } diff --git a/upup/pkg/fi/clientset_castore.go b/upup/pkg/fi/clientset_castore.go index e6817ab04a..eeb6c34a6e 100644 --- a/upup/pkg/fi/clientset_castore.go +++ b/upup/pkg/fi/clientset_castore.go @@ -155,14 +155,13 @@ func FindPrimary(keyset *kops.Keyset) *kops.KeysetItem { return primary } -// FindPrimaryKeypair implements PKI::FindPrimaryKeypair -func (c *ClientsetCAStore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error) { - return FindPrimaryKeypair(c, name) +// FindPrimaryKeypair implements pki.Keystore +func (c *ClientsetCAStore) FindPrimaryKeypair(ctx context.Context, name string) (*pki.Certificate, *pki.PrivateKey, error) { + return FindPrimaryKeypair(ctx, c, name) } -// FindKeyset implements CAStore::FindKeyset -func (c *ClientsetCAStore) FindKeyset(name string) (*Keyset, error) { - ctx := context.TODO() +// FindKeyset implements KeystoreReader. +func (c *ClientsetCAStore) FindKeyset(ctx context.Context, name string) (*Keyset, error) { return c.loadKeyset(ctx, name) } diff --git a/upup/pkg/fi/fitasks/keypair.go b/upup/pkg/fi/fitasks/keypair.go index 8c9df65c81..71a948bd04 100644 --- a/upup/pkg/fi/fitasks/keypair.go +++ b/upup/pkg/fi/fitasks/keypair.go @@ -69,12 +69,14 @@ func (e *Keypair) CompareWithID() *string { } func (e *Keypair) Find(c *fi.CloudupContext) (*Keypair, error) { + ctx := c.Context() + name := fi.ValueOf(e.Name) if name == "" { return nil, nil } - keyset, err := c.T.Keystore.FindKeyset(name) + keyset, err := c.T.Keystore.FindKeyset(ctx, name) if err != nil { return nil, err } @@ -195,7 +197,7 @@ func (_ *Keypair) Render(c *fi.CloudupContext, a, e, changes *Keypair) error { if createCertificate { klog.V(2).Infof("Creating PKI keypair %q", name) - keyset, err := c.T.Keystore.FindKeyset(name) + keyset, err := c.T.Keystore.FindKeyset(ctx, name) if err != nil { return err } @@ -242,7 +244,7 @@ func (_ *Keypair) Render(c *fi.CloudupContext, a, e, changes *Keypair) error { PrivateKey: privateKey, Serial: serial, } - cert, privateKey, _, err := pki.IssueCert(&req, c.T.Keystore) + cert, privateKey, _, err := pki.IssueCert(ctx, &req, c.T.Keystore) if err != nil { return err } @@ -267,9 +269,10 @@ func (_ *Keypair) Render(c *fi.CloudupContext, a, e, changes *Keypair) error { } // Make double-sure it round-trips - _, err = c.T.Keystore.FindKeyset(name) - if err != nil { + if roundtrip, err := c.T.Keystore.FindKeyset(ctx, name); err != nil { return err + } else if roundtrip == nil { + return fmt.Errorf("unable to find created certificate %q: %w", name, err) } klog.V(8).Infof("created certificate with cn=%s", cert.Subject.CommonName) @@ -280,10 +283,14 @@ func (_ *Keypair) Render(c *fi.CloudupContext, a, e, changes *Keypair) error { if changeStoredFormat { // We fetch and reinsert the same keypair, forcing an update to our preferred format // TODO: We're assuming that we want to save in the preferred format - keyset, err := c.T.Keystore.FindKeyset(name) + keyset, err := c.T.Keystore.FindKeyset(ctx, name) if err != nil { return err } + if keyset == nil { + return fmt.Errorf("keyset %q not found", name) + } + keyset.LegacyFormat = false err = c.T.Keystore.StoreKeyset(ctx, name, keyset) if err != nil { diff --git a/upup/pkg/fi/nodeup/nodetasks/issue_cert.go b/upup/pkg/fi/nodeup/nodetasks/issue_cert.go index 9eb3f882bf..f9236fb983 100644 --- a/upup/pkg/fi/nodeup/nodetasks/issue_cert.go +++ b/upup/pkg/fi/nodeup/nodetasks/issue_cert.go @@ -18,6 +18,7 @@ package nodetasks import ( "bytes" + "context" "crypto/x509/pkix" "fmt" "hash/fnv" @@ -130,6 +131,8 @@ func (i *IssueCert) AddFileTasks(c *fi.NodeupModelBuilderContext, dir string, na } func (e *IssueCert) Run(c *fi.NodeupContext) error { + ctx := c.Context() + // Skew the certificate lifetime by up to 30 days based on information about the generating node. // This is so that different nodes created at the same time have the certificates they generated // expire at different times, but all certificates on a given node expire around the same time. @@ -155,13 +158,13 @@ func (e *IssueCert) Run(c *fi.NodeupContext) error { Validity: time.Hour * time.Duration(validHours), } - keystore, err := newStaticKeystore(e.Signer, e.KeypairID, c.T.Keystore) + keystore, err := newStaticKeystore(ctx, e.Signer, e.KeypairID, c.T.Keystore) if err != nil { return err } klog.Infof("signing certificate for %q", e.Name) - certificate, privateKey, caCertificate, err := pki.IssueCert(req, keystore) + certificate, privateKey, caCertificate, err := pki.IssueCert(ctx, req, keystore) if err != nil { return err } @@ -208,14 +211,15 @@ type staticKeystore struct { key *pki.PrivateKey } -func (s staticKeystore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error) { +// FindPrimaryKeypair implements pki.Keystore +func (s staticKeystore) FindPrimaryKeypair(ctx context.Context, name string) (*pki.Certificate, *pki.PrivateKey, error) { if name != s.keyset { return nil, nil, fmt.Errorf("wrong signer: expected %q got %q", s.keyset, name) } return s.certificate, s.key, nil } -func newStaticKeystore(signer string, keypairID string, keystore fi.KeystoreReader) (pki.Keystore, error) { +func newStaticKeystore(ctx context.Context, signer string, keypairID string, keystore fi.KeystoreReader) (pki.Keystore, error) { if signer == "" { return nil, nil } @@ -224,10 +228,13 @@ func newStaticKeystore(signer string, keypairID string, keystore fi.KeystoreRead return nil, fmt.Errorf("missing keypairID for %s", signer) } - keyset, err := keystore.FindKeyset(signer) + keyset, err := keystore.FindKeyset(ctx, signer) if err != nil { return nil, fmt.Errorf("reading keyset for %s: %v", signer, err) } + if keyset == nil { + return nil, fmt.Errorf("keyset %q not found", signer) + } item := keyset.Items[keypairID] if item == nil { diff --git a/upup/pkg/fi/vfs_castore.go b/upup/pkg/fi/vfs_castore.go index dfeae102fc..2ea0c8373b 100644 --- a/upup/pkg/fi/vfs_castore.go +++ b/upup/pkg/fi/vfs_castore.go @@ -211,8 +211,9 @@ func serializeKeysetBundle(o *kops.Keyset) ([]byte, error) { return objectData.Bytes(), nil } -func (c *VFSCAStore) FindPrimaryKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error) { - return FindPrimaryKeypair(c, name) +// FindPrimaryKeypair implements pki.Keystore +func (c *VFSCAStore) FindPrimaryKeypair(ctx context.Context, name string) (*pki.Certificate, *pki.PrivateKey, error) { + return FindPrimaryKeypair(ctx, c, name) } var legacyKeysetMappings = map[string]string{ @@ -222,7 +223,8 @@ var legacyKeysetMappings = map[string]string{ "kubernetes-ca": "ca", } -func (c *VFSCAStore) FindKeyset(id string) (*Keyset, error) { +// FindKeyset implements KeystoreReader. +func (c *VFSCAStore) FindKeyset(ctx context.Context, id string) (*Keyset, error) { keys, err := c.findPrivateKeyset(id) if keys == nil || os.IsNotExist(err) { if legacyId := legacyKeysetMappings[id]; legacyId != "" { diff --git a/upup/pkg/fi/vfs_castore_test.go b/upup/pkg/fi/vfs_castore_test.go index 97f87e4f95..88c9f3f152 100644 --- a/upup/pkg/fi/vfs_castore_test.go +++ b/upup/pkg/fi/vfs_castore_test.go @@ -137,7 +137,7 @@ spec: t.Fatalf("unexpected private/ca/keyset.yaml: %q", string(privateKeysetYaml)) } - keyset, err := s.FindKeyset("kubernetes-ca") + keyset, err := s.FindKeyset(ctx, "kubernetes-ca") if err != nil { t.Fatalf("error reading certificate pool: %v", err) }