mirror of
https://github.com/siderolabs/talos.git
synced 2025-09-30 10:11:26 +02:00
feat: gen secrets from kubernetes pki dir
This PR allows the ability to generate `secrets.yaml` (`talosctl gen secrets`) using a Kubernetes PKI directory path (e.g. `/etc/kubernetes/pki`) as input. Also introduces the flag `--kubernetes-bootstrap-token` to be able to set a static Kubernetes bootstrap token to the generated `secrets.yaml` file instead of a randomly-generated one. Closes siderolabs/talos#5894. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
This commit is contained in:
parent
a1d7b535ad
commit
a75fe7600d
@ -16,8 +16,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var genSecretsCmdFlags struct {
|
var genSecretsCmdFlags struct {
|
||||||
outputFile string
|
outputFile string
|
||||||
talosVersion string
|
talosVersion string
|
||||||
|
fromKubernetesPki string
|
||||||
|
kubernetesBootstrapToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
// genSecretsCmd represents the `gen secrets` command.
|
// genSecretsCmd represents the `gen secrets` command.
|
||||||
@ -27,18 +29,32 @@ var genSecretsCmd = &cobra.Command{
|
|||||||
Long: ``,
|
Long: ``,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
genOptions := make([]generate.GenOption, 0, 1)
|
var (
|
||||||
|
secretsBundle *generate.SecretsBundle
|
||||||
|
versionContract *config.VersionContract
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
if genSecretsCmdFlags.talosVersion != "" {
|
if genSecretsCmdFlags.talosVersion != "" {
|
||||||
versionContract, err := config.ParseContractFromVersion(genSecretsCmdFlags.talosVersion)
|
versionContract, err = config.ParseContractFromVersion(genSecretsCmdFlags.talosVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid talos-version: %w", err)
|
return fmt.Errorf("invalid talos-version: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
genOptions = append(genOptions, generate.WithVersionContract(versionContract))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
secretsBundle, err := generate.NewSecretsBundle(generate.NewClock(), genOptions...)
|
if genSecretsCmdFlags.fromKubernetesPki != "" {
|
||||||
|
secretsBundle, err = generate.NewSecretsBundleFromKubernetesPKI(genSecretsCmdFlags.fromKubernetesPki,
|
||||||
|
genSecretsCmdFlags.kubernetesBootstrapToken, versionContract)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create secrets bundle: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeSecretsBundleToFile(secretsBundle)
|
||||||
|
}
|
||||||
|
|
||||||
|
secretsBundle, err = generate.NewSecretsBundle(generate.NewClock(),
|
||||||
|
generate.WithVersionContract(versionContract),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create secrets bundle: %w", err)
|
return fmt.Errorf("failed to create secrets bundle: %w", err)
|
||||||
}
|
}
|
||||||
@ -59,6 +75,8 @@ func writeSecretsBundleToFile(bundle *generate.SecretsBundle) error {
|
|||||||
func init() {
|
func init() {
|
||||||
genSecretsCmd.Flags().StringVarP(&genSecretsCmdFlags.outputFile, "output-file", "o", "secrets.yaml", "path of the output file")
|
genSecretsCmd.Flags().StringVarP(&genSecretsCmdFlags.outputFile, "output-file", "o", "secrets.yaml", "path of the output file")
|
||||||
genSecretsCmd.Flags().StringVar(&genSecretsCmdFlags.talosVersion, "talos-version", "", "the desired Talos version to generate secrets bundle for (backwards compatibility, e.g. v0.8)")
|
genSecretsCmd.Flags().StringVar(&genSecretsCmdFlags.talosVersion, "talos-version", "", "the desired Talos version to generate secrets bundle for (backwards compatibility, e.g. v0.8)")
|
||||||
|
genSecretsCmd.Flags().StringVarP(&genSecretsCmdFlags.fromKubernetesPki, "from-kubernetes-pki", "p", "", "use a Kubernetes PKI directory (e.g. /etc/kubernetes/pki) as input")
|
||||||
|
genSecretsCmd.Flags().StringVarP(&genSecretsCmdFlags.kubernetesBootstrapToken, "kubernetes-bootstrap-token", "t", "", "use the provided bootstrap token as input")
|
||||||
|
|
||||||
Cmd.AddCommand(genSecretsCmd)
|
Cmd.AddCommand(genSecretsCmd)
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,23 @@ machine:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Patch format is detected automatically.
|
Patch format is detected automatically.
|
||||||
|
"""
|
||||||
|
|
||||||
|
[notes.gen-secrets-from-pki]
|
||||||
|
title = "Generating Talos secrets from PKI directory"
|
||||||
|
description="""\
|
||||||
|
It is now possible to generate a secrets bundle from a Kubernetes PKI directory (e.g. `/etc/kubernetes/pki`).
|
||||||
|
|
||||||
|
You can also specify a bootstrap token to be used in the secrets bundle.
|
||||||
|
|
||||||
|
This secrets bundle can then be used to generate a machine config.
|
||||||
|
|
||||||
|
This facilitates migrating clusters (e.g. created using `kubeadm`) to Talos.
|
||||||
|
|
||||||
|
```
|
||||||
|
talosctl gen secrets --kubernetes-bootstrap-token znzio1.1ifu15frz7jd59pv --from-kubernetes-pki /etc/kubernetes/pki
|
||||||
|
talosctl gen config --with-secrets secrets.yaml my-cluster https://172.20.0.1:6443
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[make_deps]
|
[make_deps]
|
||||||
|
@ -9,7 +9,6 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
@ -209,11 +208,56 @@ func (suite *GenSuite) TestSecrets() {
|
|||||||
suite.RunCLI([]string{"gen", "secrets"}, base.StdoutEmpty())
|
suite.RunCLI([]string{"gen", "secrets"}, base.StdoutEmpty())
|
||||||
suite.Assert().FileExists("secrets.yaml")
|
suite.Assert().FileExists("secrets.yaml")
|
||||||
|
|
||||||
|
defer os.Remove("secrets.yaml") // nolint:errcheck
|
||||||
|
|
||||||
suite.RunCLI([]string{"gen", "secrets", "--output-file", "/tmp/secrets2.yaml"}, base.StdoutEmpty())
|
suite.RunCLI([]string{"gen", "secrets", "--output-file", "/tmp/secrets2.yaml"}, base.StdoutEmpty())
|
||||||
suite.Assert().FileExists("/tmp/secrets2.yaml")
|
suite.Assert().FileExists("/tmp/secrets2.yaml")
|
||||||
|
|
||||||
|
defer os.Remove("/tmp/secrets2.yaml") // nolint:errcheck
|
||||||
|
|
||||||
suite.RunCLI([]string{"gen", "secrets", "-o", "secrets3.yaml", "--talos-version", "v0.8"}, base.StdoutEmpty())
|
suite.RunCLI([]string{"gen", "secrets", "-o", "secrets3.yaml", "--talos-version", "v0.8"}, base.StdoutEmpty())
|
||||||
suite.Assert().FileExists("secrets3.yaml")
|
suite.Assert().FileExists("secrets3.yaml")
|
||||||
|
|
||||||
|
defer os.Remove("secrets3.yaml") // nolint:errcheck
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSecretsWithPKIDirAndToken ...
|
||||||
|
func (suite *GenSuite) TestSecretsWithPKIDirAndToken() {
|
||||||
|
path := "/tmp/secrets-with-pki-dir-and-token.yaml"
|
||||||
|
|
||||||
|
tempDir := suite.T().TempDir()
|
||||||
|
|
||||||
|
dir, err := writeKubernetesPKIFiles(tempDir)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
defer os.RemoveAll(dir) //nolint:errcheck
|
||||||
|
|
||||||
|
suite.RunCLI([]string{
|
||||||
|
"gen", "secrets", "--from-kubernetes-pki", dir,
|
||||||
|
"--kubernetes-bootstrap-token", "test-token",
|
||||||
|
"--output-file", path,
|
||||||
|
}, base.StdoutEmpty())
|
||||||
|
|
||||||
|
suite.Assert().FileExists(path)
|
||||||
|
|
||||||
|
defer os.Remove(path) //nolint:errcheck
|
||||||
|
|
||||||
|
secretsYaml, err := os.ReadFile(path)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
var secrets generate.SecretsBundle
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(secretsYaml, &secrets)
|
||||||
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
|
suite.Assert().Equal("test-token", secrets.Secrets.BootstrapToken, "bootstrap token does not match")
|
||||||
|
suite.Assert().Equal(pkiCACrt, secrets.Certs.K8s.Crt, "k8s ca cert does not match")
|
||||||
|
suite.Assert().Equal(pkiCAKey, secrets.Certs.K8s.Key, "k8s ca key does not match")
|
||||||
|
suite.Assert().Equal(pkiFrontProxyCACrt, secrets.Certs.K8sAggregator.Crt, "k8s aggregator ca cert does not match")
|
||||||
|
suite.Assert().Equal(pkiFrontProxyCAKey, secrets.Certs.K8sAggregator.Key, "k8s aggregator ca key does not match")
|
||||||
|
suite.Assert().Equal(pkiSAKey, secrets.Certs.K8sServiceAccount.Key, "k8s service account key does not match")
|
||||||
|
suite.Assert().Equal(pkiEtcdCACrt, secrets.Certs.Etcd.Crt, "etcd ca cert does not match")
|
||||||
|
suite.Assert().Equal(pkiEtcdCAKey, secrets.Certs.Etcd.Key, "etcd ca key does not match")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestConfigWithSecrets tests the gen config command with secrets provided.
|
// TestConfigWithSecrets tests the gen config command with secrets provided.
|
||||||
@ -221,7 +265,7 @@ func (suite *GenSuite) TestConfigWithSecrets() {
|
|||||||
suite.RunCLI([]string{"gen", "secrets"}, base.StdoutEmpty())
|
suite.RunCLI([]string{"gen", "secrets"}, base.StdoutEmpty())
|
||||||
suite.Assert().FileExists("secrets.yaml")
|
suite.Assert().FileExists("secrets.yaml")
|
||||||
|
|
||||||
secretsYaml, err := ioutil.ReadFile("secrets.yaml")
|
secretsYaml, err := os.ReadFile("secrets.yaml")
|
||||||
suite.Assert().NoError(err)
|
suite.Assert().NoError(err)
|
||||||
|
|
||||||
suite.RunCLI([]string{"gen", "config", "foo", "https://192.168.0.1:6443", "--with-secrets", "secrets.yaml"})
|
suite.RunCLI([]string{"gen", "config", "foo", "https://192.168.0.1:6443", "--with-secrets", "secrets.yaml"})
|
||||||
|
67
internal/integration/cli/pki.go
Normal file
67
internal/integration/cli/pki.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed "testdata/pki/ca.crt"
|
||||||
|
pkiCACrt []byte
|
||||||
|
//go:embed "testdata/pki/ca.key"
|
||||||
|
pkiCAKey []byte
|
||||||
|
//go:embed "testdata/pki/front-proxy-ca.crt"
|
||||||
|
pkiFrontProxyCACrt []byte
|
||||||
|
//go:embed "testdata/pki/front-proxy-ca.key"
|
||||||
|
pkiFrontProxyCAKey []byte
|
||||||
|
//go:embed "testdata/pki/sa.key"
|
||||||
|
pkiSAKey []byte
|
||||||
|
//go:embed "testdata/pki/etcd/ca.crt"
|
||||||
|
pkiEtcdCACrt []byte
|
||||||
|
//go:embed "testdata/pki/etcd/ca.key"
|
||||||
|
pkiEtcdCAKey []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeKubernetesPKIFiles(dir string) (string, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(dir, "ca.crt"), pkiCACrt, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(dir, "ca.key"), pkiCAKey, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(dir, "front-proxy-ca.crt"), pkiFrontProxyCACrt, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(dir, "front-proxy-ca.key"), pkiFrontProxyCAKey, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(dir, "sa.key"), pkiSAKey, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
etcdDir := filepath.Join(dir, "etcd")
|
||||||
|
if err = os.Mkdir(etcdDir, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(etcdDir, "ca.crt"), pkiEtcdCACrt, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.WriteFile(filepath.Join(etcdDir, "ca.key"), pkiEtcdCAKey, 0o777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dir, nil
|
||||||
|
}
|
19
internal/integration/cli/testdata/pki/ca.crt
vendored
Normal file
19
internal/integration/cli/testdata/pki/ca.crt
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
|
||||||
|
cm5ldGVzMB4XDTIyMDcwODExMTM0OFoXDTMyMDcwNTExMTM0OFowFTETMBEGA1UE
|
||||||
|
AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGI
|
||||||
|
T8ncEbVJ7LtRTZY6Vc2bXlMtagzCqpP+29H7HtsgV4T64QJsPRnfCh0PzOit7JJq
|
||||||
|
SRj526wHZRfSvu0M9wZ2KaC4MVDMP2KhBUKW63nUmdXQMf+z1gHKzCMloAMa0Avb
|
||||||
|
DVsoc9NaiiHX8m59gX328xEHQjNxnNGIretBjsjZw/Xeo2BflVXahnnxMVJqnzEa
|
||||||
|
0jpnGh5BaO4aPKDrJbyELz8Y8F+NGJ2zkSVtBh0gYZrejnioEiSFkSvcxDw3Xhg2
|
||||||
|
QL+NUsRrhYHq10apJhuSkPkraCogbHlN33dslJ+I85xszKt437gGkpDoTKXaxe9L
|
||||||
|
f9xB40PgToK9QfAOIFMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
|
||||||
|
/wQFMAMBAf8wHQYDVR0OBBYEFF06xQ3JTko0LcX5pvAdp+mLFWgMMBUGA1UdEQQO
|
||||||
|
MAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBAIkhsj6yVvEoN4q7nj97
|
||||||
|
vY0RpAOyysmhigHK0miioKsd94GDb+aMBYFLKliU48B5/n/KXblu7xsTane8uB3C
|
||||||
|
VeBywkDXLN2a9ax4BaxIkleDOX1xZN4BtxIfdU1QGhFQU0JPDCMxbDjbfN2Kg2Wi
|
||||||
|
iESrsXYKDq2pLNeQdszxPGNlAOjssVHY6IivWOcMRHP0yCDTl5ooq180+U7smFdz
|
||||||
|
NM/6udMOhsgh6bUCeMu9mhaPXMBmK0Lcd68PFunAA8q7a5OfTgIhGC9n7Q0L6CMw
|
||||||
|
7yXb97bd9bPZqeiuw7G7+UiNkJrBdIMc0AYE+wG44Uxu9usrGZZt6zLYzfnJ2vRZ
|
||||||
|
qac=
|
||||||
|
-----END CERTIFICATE-----
|
27
internal/integration/cli/testdata/pki/ca.key
vendored
Normal file
27
internal/integration/cli/testdata/pki/ca.key
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEAsYhPydwRtUnsu1FNljpVzZteUy1qDMKqk/7b0fse2yBXhPrh
|
||||||
|
Amw9Gd8KHQ/M6K3skmpJGPnbrAdlF9K+7Qz3BnYpoLgxUMw/YqEFQpbredSZ1dAx
|
||||||
|
/7PWAcrMIyWgAxrQC9sNWyhz01qKIdfybn2BffbzEQdCM3Gc0Yit60GOyNnD9d6j
|
||||||
|
YF+VVdqGefExUmqfMRrSOmcaHkFo7ho8oOslvIQvPxjwX40YnbORJW0GHSBhmt6O
|
||||||
|
eKgSJIWRK9zEPDdeGDZAv41SxGuFgerXRqkmG5KQ+StoKiBseU3fd2yUn4jznGzM
|
||||||
|
q3jfuAaSkOhMpdrF70t/3EHjQ+BOgr1B8A4gUwIDAQABAoIBAQCIvqY2pfw916Mw
|
||||||
|
5X8NqAFPTc1p5CE7kvYw6K4JH5S01ESVeWi3pQerVdFEcVc0IkOGw7dqNYqvB0Mn
|
||||||
|
Bn1pugLMR1fpI/dYdPqdzclvcTAPt2KG/saEXtEIsFxs9h46RfzaJPA0twQAWEzt
|
||||||
|
pJhn4uRLUlwHUb/8QBa6jrzn6KdCrLC0jc0g8c77x3omkfy0chug7q2s/yX2MwEX
|
||||||
|
p5pbyPiGZkNIjuDeic3D0ssrH7v7gEYBdybgl78LrLkKA8gEFLrGvrT5nuLYhxkF
|
||||||
|
dhRu3+p9mhhKmJQndto8Y4WeYhXZ7qN2YZbfcv1Xni6cq4UhLmr2czRaK0KVZ15H
|
||||||
|
kzYh0I8BAoGBAOTjpoVVc+IgVJnGeglrJP8zOKEiwj3R+eF9DiQuTdnop0SBiqYB
|
||||||
|
JT6/b/apdYEGz2nBs3M1k6CmNrkzGADMNins7m1MRHkljRqu1IHSF3Us2yifPUef
|
||||||
|
lEUHtXf3ANvf3YJWuGO7RT4sird/1vXE/0TCzjWEvkHc6Zvky/DCydTJAoGBAMaP
|
||||||
|
bWsiDSFpLV6iCiq18bmJJoUDnkXqnwsUVw9C978h2Hx5ysYfOUt6S6Q7UsR7hKW5
|
||||||
|
iay1aiFPBjLQyD4Ac8feZFQEQ5gFYXPEfIV3OYZDz2U+gAZp33ow7/H/73kngelV
|
||||||
|
6EXhTYgDRUwfTBOMSlzhCZwQb8Rzpv+gC3TFsmY7AoGAWewB2LIYo8bV1c/+08Jv
|
||||||
|
N39VCSERtJ3QkMDDlH1Igop/ZE+MO+mJS1yETSCIFFerlr3NlT6AMAX8y8eB75ZK
|
||||||
|
1S/K/8+NuxaAl/IFdLcoFhW4R/4/YesUogYESgwVH0yUxobxS+Ufr+xp1ut3dPie
|
||||||
|
3NG3l5j98fwrHt7FLGIqTtkCgYEAjezfDQCd2g/PuiCgm77JNRDvU4wuiVMWs1iq
|
||||||
|
keIQK7IJh4+WfN68mVKk1pMAqiiPu9VOrwBNB9nwWEoblxXDrE0t8U/K8NKHwbPk
|
||||||
|
PZHmsC2wBHIUGIF8l157Y8LIbRTsKtiY2bodLOcJlUuZmS9hx9migMbO3OC9sWG4
|
||||||
|
TpMw3RkCgYA8ssuhj5wrSQabCXbOU0pn/qbePHWfvh+DcRUXnTtRoothpqvDQxuS
|
||||||
|
73j2NB42UG7j0eWRK993ONGTJ/QNMAJxXwLEuLFtoKHdh7pkq3uFolyNzR+T0vna
|
||||||
|
awkSRmJsbuV7C4mDVHgEaqcEzv/VyeAokw/hqB1Ga9fvauj6MDPshw==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
18
internal/integration/cli/testdata/pki/etcd/ca.crt
vendored
Normal file
18
internal/integration/cli/testdata/pki/etcd/ca.crt
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC9TCCAd2gAwIBAgIBADANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwdldGNk
|
||||||
|
LWNhMB4XDTIyMDcwODExMTM0OFoXDTMyMDcwNTExMTM0OFowEjEQMA4GA1UEAxMH
|
||||||
|
ZXRjZC1jYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOgw+tA7odeO
|
||||||
|
H5gKPlhWBjijuNoLlMCJSkGG0Ca/fI6Bk2Y+fzuVv8NWsRrhML3dEWJgXccMhoG0
|
||||||
|
v9MatmvF5nYfm802ZaDCsA6RdJG3PygRTw69pmC4ETfv0+YXpFFfFBeWWb9MsXIP
|
||||||
|
ULooepYy4bWvjG7ZDCeFQ8ACHGE17U0O5rFBqiY0okBjSkl1/oHSzlAVCxa4dOaK
|
||||||
|
/Vj8A8CefT18JZ+jzAbgN7jRm1GWzYTWqACVa5CnRDYRglrZr9DLvaj0ASqck5DD
|
||||||
|
zdJYVQJeVqS7L8qghXfbXzxlkKesRtQsj7V2trpDBuDASJPk6ZmwEWlaI0Wdc3eK
|
||||||
|
nYHgaWybLykCAwEAAaNWMFQwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB/wQFMAMB
|
||||||
|
Af8wHQYDVR0OBBYEFKN5e0IuTpOoTqWB9+MQp/k/OgXgMBIGA1UdEQQLMAmCB2V0
|
||||||
|
Y2QtY2EwDQYJKoZIhvcNAQELBQADggEBAGmGUUqeGe4RXd3kZGTRcdJMo7OkuEK5
|
||||||
|
hH/FHfrLLc3VNoWQafdq4oVrF9bwqDUPRuPgrXl+QY+s4/ztDyHmuKGdLWIT2dCE
|
||||||
|
0Ztnpe17VoMrkJxmFvKEWrT74EnT0QIeFs+lf8+SJWTLYKBRpGrsQKq84uds++gV
|
||||||
|
BPLuu8Z0e5vvkAFnX8m65SqyZwKfs3HuzaAnA57VGSJHCBrnKojsP8JdlWeQiStG
|
||||||
|
CtmzePeLqjVJnpNF/n1ST5Ewr4Kq/Cvf707gzs+spn0bt97QyNke6b24ZrkpUNu6
|
||||||
|
T/0bImLeYiGmSanRF3hAdN7IV0ah7tYOpmwk560kyF8tmd8jcKFgEd8=
|
||||||
|
-----END CERTIFICATE-----
|
27
internal/integration/cli/testdata/pki/etcd/ca.key
vendored
Normal file
27
internal/integration/cli/testdata/pki/etcd/ca.key
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEA6DD60Duh144fmAo+WFYGOKO42guUwIlKQYbQJr98joGTZj5/
|
||||||
|
O5W/w1axGuEwvd0RYmBdxwyGgbS/0xq2a8Xmdh+bzTZloMKwDpF0kbc/KBFPDr2m
|
||||||
|
YLgRN+/T5hekUV8UF5ZZv0yxcg9Quih6ljLhta+MbtkMJ4VDwAIcYTXtTQ7msUGq
|
||||||
|
JjSiQGNKSXX+gdLOUBULFrh05or9WPwDwJ59PXwln6PMBuA3uNGbUZbNhNaoAJVr
|
||||||
|
kKdENhGCWtmv0Mu9qPQBKpyTkMPN0lhVAl5WpLsvyqCFd9tfPGWQp6xG1CyPtXa2
|
||||||
|
ukMG4MBIk+TpmbARaVojRZ1zd4qdgeBpbJsvKQIDAQABAoIBAHI8xun0rOfU8Q5o
|
||||||
|
28uyZ1UumCAPWpxv76zVm0u1Ip8qeU7wqMC0KKj+2hwTd1uyjH8OUpVAQF1IhKhk
|
||||||
|
mCPmNkEfxBPvE4lIwD4qqmOW+OfJvE/QVy924GHZCTRHpXyzfrssKfPI0/T+PAWb
|
||||||
|
LNUBK7OsLzfKagR3uKGbaEMbuSkTn5zeCJ1vrFAuCaLmeauBsnoV7Z9AlbG6t8sp
|
||||||
|
hyD0O+pDPGuc+J99suGiysndwjczqntIKXcdgba2XxRE0QHM+ZYDPpyvCggKfoUH
|
||||||
|
sQ9Vz/UHpqTv8pbrTSZK59E8+16YfFyFC+iwTnTzoBAkO6NIivDTQvLcipweZEzt
|
||||||
|
5146EEECgYEA6O+Pd1tdkTVHLgSkKrkBo4p3g2iBFl626g7vlZGvDjVNNPBWwk5f
|
||||||
|
j3PbMKPfUfr96YB86lbetDzYdiB5LrLW5xG2GaSRziGI1/Tgdp6aR142TNljiEu7
|
||||||
|
dv4v3eAR5VfiA5CGera+k1VzKLIygfCDkUWWdG17LvVdHFtjN6XVU2UCgYEA/y6M
|
||||||
|
hZbZqCX9cx58rhJ38YvH9fdWSzw1r9crgM40uPHE4SHvin6/lR/rbNU4Geg/b4bn
|
||||||
|
FWnffCem8ov2tXcFe/ZBM8ZWrsRGDinkTh8dReh8ujE90YOqf3YSRYgUvSx8ITUn
|
||||||
|
zqhe43sGVAelKeVKPW/3Ok7RJXnRRsDIbSmfqnUCgYB7sDmON4XHxXK2jOBfjz2/
|
||||||
|
iZdMwAFLz59xSd0Onv1FnigRJE3tf5BerDaH7Xx4G78YbpHmHZrEOkr27udqVKyo
|
||||||
|
pk777tc9jbEMe4t1cWKa4vwScpzXkt9IoFDqkEDwd2ocWnIOV1t7ALTVt0n6laxH
|
||||||
|
R5xM1pXCqad3l09oDTbpwQKBgDlHwqVOCkeTV4QayNPuM1xWCymsPoOe3VI+U3aT
|
||||||
|
UwRcyNvcWT/WWbzosFj6t6AhIPQw7PhCjrb406HIRzXOpL2Btnsfv191kWAmiSf8
|
||||||
|
Ff8WQ8ErwnugOYpo/4r6E+Wu8aImo2vhIYOgnvgHy0xPOs31ryI4hPwLjy15osPW
|
||||||
|
Pw/tAoGBAKaT53bqIl+wzltM2ROtH9ppA98prDPM0GyZMhFed+XMLAkUX3qmFtj5
|
||||||
|
k51bhaq7ER4yByHX17Q7y3SoJ5NpccmFUhWhttRf/IraWEKsHXW6OY22wvtZN9Lx
|
||||||
|
Eh+rpZsjcozUCaoQWkOf20UpBSltIV5U4GmSpthnj0+zaRrorxWx
|
||||||
|
-----END RSA PRIVATE KEY-----
|
19
internal/integration/cli/testdata/pki/front-proxy-ca.crt
vendored
Normal file
19
internal/integration/cli/testdata/pki/front-proxy-ca.crt
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDEw5mcm9u
|
||||||
|
dC1wcm94eS1jYTAeFw0yMjA3MDgxMTEzNDhaFw0zMjA3MDUxMTEzNDhaMBkxFzAV
|
||||||
|
BgNVBAMTDmZyb250LXByb3h5LWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||||
|
CgKCAQEA4thL1utf/iXxylt24O3o3IV7oif5tiYR4SN9YnVb/GLyVtVdHuzPpigw
|
||||||
|
j+S7aw3mldNHVWbIPq9GncvVsgvlJYHu53WRzVfV7tAylt/ssSqHFv/p1e6rC2m9
|
||||||
|
hETHUZjSs8v0APWi8pfh15lJPqLS1lGF3QPVCPdc1t+8dBVnx8wnTgGVE7FVLjmc
|
||||||
|
3qIcXTR1TfcB4+X1ZnY5FNK7kR/kgIS64uZqntyNSW5W0SCFgWQClwwkzVpo4v/Y
|
||||||
|
sCHiWI7cIuXHTTd7ntHJab1Og1jAPNEmENvEtza1SqGTSEUQs5wjS+p+ii5E09b3
|
||||||
|
Nufj1e8hJaodTxr+24hoFcYxWIgxhwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAqQw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUvw91sUxAgIX7zdqTKwJ0Sdxa9TUw
|
||||||
|
GQYDVR0RBBIwEIIOZnJvbnQtcHJveHktY2EwDQYJKoZIhvcNAQELBQADggEBAGHW
|
||||||
|
snsEJkN3d2vNJuFu6IVKurEZM8UbwHebJ5fQUHpCOKpFqSMdngF8rdcYNmHeUFMv
|
||||||
|
Qf9Fkm9nwKOhO9hApsQad7UgJ98YCzE+heTye7nKjrga+2lsJN/T3SgJGiAEkVjP
|
||||||
|
rq2SQ4MLCp56PyFI5CL9zqtjuXCI8Uhqqfru6tJEA75GA6VJZmfiOgzFQum7DeC2
|
||||||
|
9dNcvQb8p91LIl5tjvuTgPbJDjF1YX4n0iwoiA05e+rPrsPhyySQnJwFgTi+hqPZ
|
||||||
|
cBUPwVDYeiHseRbj3ODOoCv6PO4koO5m+tiFeUXJTynMbCUkyJqZ11TAYC6snHxi
|
||||||
|
mg+fblveomK3F3hLFdk=
|
||||||
|
-----END CERTIFICATE-----
|
27
internal/integration/cli/testdata/pki/front-proxy-ca.key
vendored
Normal file
27
internal/integration/cli/testdata/pki/front-proxy-ca.key
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEA4thL1utf/iXxylt24O3o3IV7oif5tiYR4SN9YnVb/GLyVtVd
|
||||||
|
HuzPpigwj+S7aw3mldNHVWbIPq9GncvVsgvlJYHu53WRzVfV7tAylt/ssSqHFv/p
|
||||||
|
1e6rC2m9hETHUZjSs8v0APWi8pfh15lJPqLS1lGF3QPVCPdc1t+8dBVnx8wnTgGV
|
||||||
|
E7FVLjmc3qIcXTR1TfcB4+X1ZnY5FNK7kR/kgIS64uZqntyNSW5W0SCFgWQClwwk
|
||||||
|
zVpo4v/YsCHiWI7cIuXHTTd7ntHJab1Og1jAPNEmENvEtza1SqGTSEUQs5wjS+p+
|
||||||
|
ii5E09b3Nufj1e8hJaodTxr+24hoFcYxWIgxhwIDAQABAoIBAQDa55WQCcWxkNZa
|
||||||
|
y5bVimBbZeif2+nKj8RTOZdGyzAAR0/K4c0iCa58jm4GfdkqftiUnrVIwY3dh/Ei
|
||||||
|
V1CZp4byggeUjs0rlmaZNYqMM/zKHtsMI9t4mf+vXNQI7wJVSJ+T5+5IesJLTqwf
|
||||||
|
DQo0ipXhQfxnAsqzA1ow9Ol8MCfdEeFL5SFaVNiNhany/7PR0letngwMIAje6arY
|
||||||
|
6dPzjPYDsCjMTjoNarUADIZeVxMdbOCmiMy+yGDZlgV80fK0+Fw81axot2KOufhy
|
||||||
|
CvqClUlJV5Csz2egHuThuVd39kX2vAAGXdPEUbXga1JTDB3cQiHXJo0hLUsUGniS
|
||||||
|
6KdsJOyRAoGBAOmNX/V7awLiVyWsRLTNr1IeoMwHeS3Wdt5/nedqh6p2fLpfbN1D
|
||||||
|
M8R29yqvNn1YmpZsDBhQlnddq7i7OEKjSODwNnLPys6fqalsIY/AIRJPOmHvVJl6
|
||||||
|
er4scaiGXA/FztvxGGQh4W92+Nb69dCXXXcG1QUljr+uGwrIGXc8aqzpAoGBAPil
|
||||||
|
4qGf/0s3Fv0tyLj+ZRWVjg5o4s/IsJyGRFc6RplU65y9VL9WsYvi5+d06w7lovac
|
||||||
|
omycJ/z+HiqTLcixdcHse54N9HHO5Ekui6cRbGAOdlzgS84TxYrmQK/FQkFvlcmO
|
||||||
|
rsfkDMmAgBc2yGP3N5IL60u90N2Kf3OiT5aHoCTvAoGAamdwioS6EkxQa+d6Pe1f
|
||||||
|
rMgrdgkJmmqVKXV22VHdkTn+RWLoVD4jvaR9o0LEToMpmtKLCCDfDG7up3EUhreh
|
||||||
|
ommOROyKd2yifX+4Iqfj6VWTQb8qCeqVNUNGXQMpuj3iqq3C8QvGi2PmpvsbNvdf
|
||||||
|
K7U/I+MikA2gYF8dywcJitECgYArDe5UNjQqffuJE2hyP/qY5jCW5ip/+Cw8rjMf
|
||||||
|
N4QKAN5bYZ1PFF/h7QRi26foCHNTaIPncpKqCAaJMLr4yWGulphBIgF1w3FcCqc7
|
||||||
|
4pR1fYuZQW1e3aWTC5Of2/RBCGVTZVV2X1KngYyseFvyk1gX/eBcWR3VfqnbB/vo
|
||||||
|
AMwGGQKBgB/MXrB2Z61WlxR0Y289k+5gjUSS9foZIkCjr1TFDvLbEStAW8Z3WFcS
|
||||||
|
Gxzjs5s45VO3+KRRd3591WHaPWcVdNze+y5ICUr4u3WSBKg8D+9H3cMKWq8QLCRP
|
||||||
|
bgMDGq8TzTLdGmb9vw3n5OG2aAQUQfwoAp+uUwh2EDMDYixYd2UJ
|
||||||
|
-----END RSA PRIVATE KEY-----
|
27
internal/integration/cli/testdata/pki/sa.key
vendored
Normal file
27
internal/integration/cli/testdata/pki/sa.key
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEA0H28tj4Zgoj5y+/NF7Dhrf96+TQUolLR5j4YqoxbFRvgWtPE
|
||||||
|
0JFueoC0n6v4l58z4vog+1JjPHMO8rr0W3q9o/wWaY1CL3XqZJIkHI/fE/Eu1VLv
|
||||||
|
gLfDHsPevPNLczcpwXo7AadqxiUC/HRYZBJY+LA2OzWwO5ylx4YKnOzKxBXQ7a2q
|
||||||
|
qdpwZJSTTmGKyRx5pD6V5mCr47ITVAXqcjorTtJmG3zCFRhUjMscXIWC04S0IY/C
|
||||||
|
+cfMKaK4Jbqj1h2/9uNhbb55r9HdCEV/TLw+QL1Q+S6MWtng1S4Q3hyDXzB1LqfP
|
||||||
|
1brz7xl1pSLh+l0vF2pXom5zYiHlX4cAddR7MQIDAQABAoIBAAQtULeR/O7Zka+d
|
||||||
|
SU2dNJhI0wzlFzi9Ugk720CneTeuDEuljH7lOwJnS7cbOerHvMFiY4DFgMl4QKdq
|
||||||
|
SXT/u4bqiQRqWRYcVarYJrMPytdacKbDd5rrk5QtNmwwr6VKSKLgsQfyc7gui6XF
|
||||||
|
KvQuTewFk8CR7crz83pQ3CuSrulIwVny17HSE9NlXlv8SlHy7E2/a6H0UeOm7BRn
|
||||||
|
13An62CfRuBVFRd96oyTMpuNf2l+fcL5nnfM/F+tdr5MRR0pnEW2UKGdCbkTkAKd
|
||||||
|
AJnH2mmhWwbA8Gcx0Zn1X9/zu8Z3S6hTGnQmWIP25EcgipqKe/gocA9ervyR+0nb
|
||||||
|
FgwZZXECgYEA6D/mx3dI6AUY7RVIY9GexiJWLtS9O1d7PddmajoqVpwtjXT9jUf/
|
||||||
|
9BAAVWNKcIEs1t4foncJeYph6JnTrQjDz1LORC2kAjPUYhDQod/m6dqHxvjRAIns
|
||||||
|
v0NezDvWQ2v8CgklDjUc5hYtvqj51OkkbKpphRClAdJZvrlxBhXTT1UCgYEA5c/c
|
||||||
|
A6D3xIcGUrSVrjtLWUyJ9hszjjBrI5txtmwMzWDSkV3Hp1VhSfhCdIxqQxELxlxS
|
||||||
|
A8SOU0XKxRB7QiwpgHfnbGxtQ8tJ5JufIecwJkqRcD5fqQk69xva/76fNfes41L8
|
||||||
|
doNpFiu0fXbVdcB8UNN61VYsz31D/JD0qA9k5G0CgYEA5gq1egkrC7ZQ1DRqeYSd
|
||||||
|
8b79AnHx5Z9nEQAUD1ABs7wKWrzwkEoqugJHckxg5ULtuP5W80NY/SwWgqArTI8L
|
||||||
|
9IUejeVvOEdCLMhe/peaTzQHnQvDaPc0qtX+RelW9300LnSUYZg2QajiMqGIpF0x
|
||||||
|
mPjKf+TWrBFAl2tzCgYAQekCgYEAukqjaXWlI/To1UZ6R8DdNchr1cr7Ifpx/21U
|
||||||
|
4rH4NsyUJS7GWAlIUnQjOuNQiIla6DOScGd3kF11IAZaRKwUAIYyXZwPfvNeNSlJ
|
||||||
|
+Gu2hnPQLhMB7L8Ew6gbAVH/MfpSdfyhl1izaTuIlmQsacXdgI/OdP3kWVaMNEM1
|
||||||
|
cL755IkCgYAv10G49Mc57WBi6knRHM2cXbYVxjzedJf8zBnAYkQoLdRiYT6uj34U
|
||||||
|
hI1EajSfXYJ2t8PG5nbHMNHAEbYNBikhjDvSrZW+HaTmjsVGV25cqCHPy7giSqVS
|
||||||
|
VftcMlIX/MlTdfcYtNT4wHORZdO2P4wW/y5JSFNol4z3xB4TNXp55A==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
@ -16,6 +16,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/talos-systems/crypto/x509"
|
"github.com/talos-systems/crypto/x509"
|
||||||
@ -192,8 +194,6 @@ func (c *SystemClock) SetFixedTimestamp(t time.Time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewSecretsBundle creates secrets bundle generating all secrets or reading from the input options if provided.
|
// NewSecretsBundle creates secrets bundle generating all secrets or reading from the input options if provided.
|
||||||
//
|
|
||||||
//nolint:gocyclo
|
|
||||||
func NewSecretsBundle(clock Clock, opts ...GenOption) (*SecretsBundle, error) {
|
func NewSecretsBundle(clock Clock, opts ...GenOption) (*SecretsBundle, error) {
|
||||||
options := DefaultGenOptions()
|
options := DefaultGenOptions()
|
||||||
|
|
||||||
@ -208,115 +208,256 @@ func NewSecretsBundle(clock Clock, opts ...GenOption) (*SecretsBundle, error) {
|
|||||||
return options.Secrets, nil
|
return options.Secrets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bundle := SecretsBundle{
|
||||||
|
Clock: clock,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := populateSecretsBundle(options.VersionContract, &bundle)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bundle, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSecretsBundleFromKubernetesPKI creates secrets bundle by reading the contents
|
||||||
|
// of a Kubernetes PKI directory (typically `/etc/kubernetes/pki`) and using the provided bootstrapToken as input.
|
||||||
|
//
|
||||||
|
//nolint:gocyclo
|
||||||
|
func NewSecretsBundleFromKubernetesPKI(pkiDir, bootstrapToken string, versionContract *config.VersionContract) (*SecretsBundle, error) {
|
||||||
|
dirStat, err := os.Stat(pkiDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dirStat.IsDir() {
|
||||||
|
return nil, fmt.Errorf("%q is not a directory", pkiDir)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
etcd *x509.CertificateAuthority
|
ca *x509.PEMEncodedCertificateAndKey
|
||||||
kubernetesCA *x509.CertificateAuthority
|
etcdCA *x509.PEMEncodedCertificateAndKey
|
||||||
aggregatorCA *x509.CertificateAuthority
|
aggregatorCA *x509.PEMEncodedCertificateAndKey
|
||||||
serviceAccount *x509.ECDSAKey
|
sa *x509.PEMEncodedKey
|
||||||
talosCA *x509.CertificateAuthority
|
|
||||||
trustdInfo *TrustdInfo
|
|
||||||
kubeadmTokens *Secrets
|
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
etcd, err = NewEtcdCA(clock.Now(), options.VersionContract)
|
ca, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(pkiDir, "ca.crt"), filepath.Join(pkiDir, "ca.key"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
kubernetesCA, err = NewKubernetesCA(clock.Now(), options.VersionContract)
|
err = validatePEMEncodedCertificateAndKey(ca)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.VersionContract.SupportsAggregatorCA() {
|
etcdDir := filepath.Join(pkiDir, "etcd")
|
||||||
aggregatorCA, err = NewAggregatorCA(clock.Now(), options.VersionContract)
|
|
||||||
|
etcdCA, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(etcdDir, "ca.crt"), filepath.Join(etcdDir, "ca.key"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validatePEMEncodedCertificateAndKey(etcdCA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregatorCACrtPath := filepath.Join(pkiDir, "front-proxy-ca.crt")
|
||||||
|
_, err = os.Stat(aggregatorCACrtPath)
|
||||||
|
|
||||||
|
aggregatorCAFound := err == nil
|
||||||
|
if aggregatorCAFound && !versionContract.SupportsAggregatorCA() {
|
||||||
|
return nil, fmt.Errorf("aggregator CA found in pki dir but is not supported by the requested version")
|
||||||
|
}
|
||||||
|
|
||||||
|
if versionContract.SupportsAggregatorCA() {
|
||||||
|
aggregatorCA, err = x509.NewCertificateAndKeyFromFiles(aggregatorCACrtPath, filepath.Join(pkiDir, "front-proxy-ca.key"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validatePEMEncodedCertificateAndKey(aggregatorCA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.VersionContract.SupportsServiceAccount() {
|
saKeyPath := filepath.Join(pkiDir, "sa.key")
|
||||||
serviceAccount, err = x509.NewECDSAKey()
|
_, err = os.Stat(saKeyPath)
|
||||||
|
|
||||||
|
saKeyFound := err == nil
|
||||||
|
if saKeyFound && !versionContract.SupportsServiceAccount() {
|
||||||
|
return nil, fmt.Errorf("service account key found in pki dir but is not supported by the requested version")
|
||||||
|
}
|
||||||
|
|
||||||
|
if versionContract.SupportsServiceAccount() {
|
||||||
|
var saBytes []byte
|
||||||
|
|
||||||
|
saBytes, err = os.ReadFile(filepath.Join(pkiDir, "sa.key"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sa = &x509.PEMEncodedKey{
|
||||||
|
Key: saBytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = sa.GetKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
talosCA, err = NewTalosCA(clock.Now())
|
bundle := SecretsBundle{
|
||||||
if err != nil {
|
Secrets: &Secrets{
|
||||||
return nil, err
|
BootstrapToken: bootstrapToken,
|
||||||
}
|
|
||||||
|
|
||||||
kubeadmTokens = &Secrets{}
|
|
||||||
|
|
||||||
// Gen trustd token strings
|
|
||||||
kubeadmTokens.BootstrapToken, err = genToken(6, 16)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeadmTokens.AESCBCEncryptionSecret, err = cis.CreateEncryptionToken()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
trustdInfo = &TrustdInfo{}
|
|
||||||
|
|
||||||
// Gen trustd token strings
|
|
||||||
trustdInfo.Token, err = genToken(6, 16)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
clusterID, err := randBytes(constants.DefaultClusterIDSize)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to generate cluster ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
clusterSecret, err := randBytes(constants.DefaultClusterSecretSize)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to generate cluster secret: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := &SecretsBundle{
|
|
||||||
Cluster: &Cluster{
|
|
||||||
ID: base64.URLEncoding.EncodeToString(clusterID),
|
|
||||||
Secret: base64.StdEncoding.EncodeToString(clusterSecret),
|
|
||||||
},
|
},
|
||||||
Clock: clock,
|
|
||||||
Secrets: kubeadmTokens,
|
|
||||||
TrustdInfo: trustdInfo,
|
|
||||||
Certs: &Certs{
|
Certs: &Certs{
|
||||||
Etcd: &x509.PEMEncodedCertificateAndKey{
|
Etcd: etcdCA,
|
||||||
Crt: etcd.CrtPEM,
|
K8s: ca,
|
||||||
Key: etcd.KeyPEM,
|
K8sAggregator: aggregatorCA,
|
||||||
},
|
K8sServiceAccount: sa,
|
||||||
K8s: &x509.PEMEncodedCertificateAndKey{
|
|
||||||
Crt: kubernetesCA.CrtPEM,
|
|
||||||
Key: kubernetesCA.KeyPEM,
|
|
||||||
},
|
|
||||||
OS: &x509.PEMEncodedCertificateAndKey{
|
|
||||||
Crt: talosCA.CrtPEM,
|
|
||||||
Key: talosCA.KeyPEM,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if aggregatorCA != nil {
|
err = populateSecretsBundle(versionContract, &bundle)
|
||||||
result.Certs.K8sAggregator = &x509.PEMEncodedCertificateAndKey{
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bundle, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// populateSecretsBundle fills all the missing fields in the secrets bundle.
|
||||||
|
//
|
||||||
|
//nolint:gocyclo,cyclop
|
||||||
|
func populateSecretsBundle(versionContract *config.VersionContract, bundle *SecretsBundle) error {
|
||||||
|
if bundle.Clock == nil {
|
||||||
|
bundle.Clock = NewClock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Certs == nil {
|
||||||
|
bundle.Certs = &Certs{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Certs.Etcd == nil {
|
||||||
|
etcd, err := NewEtcdCA(bundle.Clock.Now(), versionContract)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Certs.Etcd = &x509.PEMEncodedCertificateAndKey{
|
||||||
|
Crt: etcd.CrtPEM,
|
||||||
|
Key: etcd.KeyPEM,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Certs.K8s == nil {
|
||||||
|
kubernetesCA, err := NewKubernetesCA(bundle.Clock.Now(), versionContract)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Certs.K8s = &x509.PEMEncodedCertificateAndKey{
|
||||||
|
Crt: kubernetesCA.CrtPEM,
|
||||||
|
Key: kubernetesCA.KeyPEM,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if versionContract.SupportsAggregatorCA() && bundle.Certs.K8sAggregator == nil {
|
||||||
|
aggregatorCA, err := NewAggregatorCA(bundle.Clock.Now(), versionContract)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Certs.K8sAggregator = &x509.PEMEncodedCertificateAndKey{
|
||||||
Crt: aggregatorCA.CrtPEM,
|
Crt: aggregatorCA.CrtPEM,
|
||||||
Key: aggregatorCA.KeyPEM,
|
Key: aggregatorCA.KeyPEM,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if serviceAccount != nil {
|
if versionContract.SupportsServiceAccount() && bundle.Certs.K8sServiceAccount == nil {
|
||||||
result.Certs.K8sServiceAccount = &x509.PEMEncodedKey{
|
serviceAccount, err := x509.NewECDSAKey()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{
|
||||||
Key: serviceAccount.KeyPEM,
|
Key: serviceAccount.KeyPEM,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
if bundle.Certs.OS == nil {
|
||||||
|
talosCA, err := NewTalosCA(bundle.Clock.Now())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Certs.OS = &x509.PEMEncodedCertificateAndKey{
|
||||||
|
Crt: talosCA.CrtPEM,
|
||||||
|
Key: talosCA.KeyPEM,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Secrets == nil {
|
||||||
|
bundle.Secrets = &Secrets{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Secrets.BootstrapToken == "" {
|
||||||
|
token, err := genToken(6, 16)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Secrets.BootstrapToken = token
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Secrets.AESCBCEncryptionSecret == "" {
|
||||||
|
aesCBCEncryptionSecret, err := cis.CreateEncryptionToken()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Secrets.AESCBCEncryptionSecret = aesCBCEncryptionSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.TrustdInfo == nil {
|
||||||
|
bundle.TrustdInfo = &TrustdInfo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.TrustdInfo.Token == "" {
|
||||||
|
token, err := genToken(6, 16)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.TrustdInfo.Token = token
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Cluster == nil {
|
||||||
|
bundle.Cluster = &Cluster{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Cluster.ID == "" {
|
||||||
|
clusterID, err := randBytes(constants.DefaultClusterIDSize)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to generate cluster ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Cluster.ID = base64.URLEncoding.EncodeToString(clusterID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bundle.Cluster.Secret == "" {
|
||||||
|
clusterSecret, err := randBytes(constants.DefaultClusterSecretSize)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to generate cluster secret: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle.Cluster.Secret = base64.StdEncoding.EncodeToString(clusterSecret)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSecretsBundleFromConfig creates secrets bundle using existing config.
|
// NewSecretsBundleFromConfig creates secrets bundle using existing config.
|
||||||
@ -608,3 +749,14 @@ func randBytes(size int) ([]byte, error) {
|
|||||||
|
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validatePEMEncodedCertificateAndKey(certs *x509.PEMEncodedCertificateAndKey) error {
|
||||||
|
_, err := certs.GetKey()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = certs.GetCert()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
// GenOption controls generate options specific to input generation.
|
// GenOption controls generate options specific to input generation.
|
||||||
type GenOption func(o *GenOptions) error
|
type GenOption func(o *GenOptions) error
|
||||||
|
|
||||||
// WithEndpointList specifies endpoints to use when acessing Talos cluster.
|
// WithEndpointList specifies endpoints to use when accessing Talos cluster.
|
||||||
func WithEndpointList(endpoints []string) GenOption {
|
func WithEndpointList(endpoints []string) GenOption {
|
||||||
return func(o *GenOptions) error {
|
return func(o *GenOptions) error {
|
||||||
o.EndpointList = endpoints
|
o.EndpointList = endpoints
|
||||||
|
@ -1253,9 +1253,11 @@ talosctl gen secrets [flags]
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help help for secrets
|
-p, --from-kubernetes-pki string use a Kubernetes PKI directory (e.g. /etc/kubernetes/pki) as input
|
||||||
-o, --output-file string path of the output file (default "secrets.yaml")
|
-h, --help help for secrets
|
||||||
--talos-version string the desired Talos version to generate secrets bundle for (backwards compatibility, e.g. v0.8)
|
-t, --kubernetes-bootstrap-token string use the provided bootstrap token as input
|
||||||
|
-o, --output-file string path of the output file (default "secrets.yaml")
|
||||||
|
--talos-version string the desired Talos version to generate secrets bundle for (backwards compatibility, e.g. v0.8)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
Loading…
x
Reference in New Issue
Block a user