Add support for custom API Server CA certificate
Signed-off-by: Joe Nathan Abellard <contact@jabellard.com>
This commit is contained in:
parent
6795dba9d1
commit
91322e2f5f
|
@ -3673,6 +3673,32 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
customCertificate:
|
||||||
|
description: |-
|
||||||
|
CustomCertificate specifies the configuration to customize the certificates
|
||||||
|
for Karmada components or control the certificate generation process, such as
|
||||||
|
the algorithm, validity period, etc.
|
||||||
|
Currently, it only supports customizing the CA certificate for limited components.
|
||||||
|
properties:
|
||||||
|
apiServerCACert:
|
||||||
|
description: |-
|
||||||
|
APIServerCACert references a Kubernetes secret containing the CA certificate
|
||||||
|
for component karmada-apiserver.
|
||||||
|
The secret must contain the following data keys:
|
||||||
|
- tls.crt: The TLS certificate.
|
||||||
|
- tls.key: The TLS private key.
|
||||||
|
If specified, this CA will be used to issue client certificates for
|
||||||
|
all components that access the APIServer as clients.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace is the namespace for the resource being
|
||||||
|
referenced.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
featureGates:
|
featureGates:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
|
@ -3673,6 +3673,32 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
customCertificate:
|
||||||
|
description: |-
|
||||||
|
CustomCertificate specifies the configuration to customize the certificates
|
||||||
|
for Karmada components or control the certificate generation process, such as
|
||||||
|
the algorithm, validity period, etc.
|
||||||
|
Currently, it only supports customizing the CA certificate for limited components.
|
||||||
|
properties:
|
||||||
|
apiServerCACert:
|
||||||
|
description: |-
|
||||||
|
APIServerCACert references a Kubernetes secret containing the CA certificate
|
||||||
|
for component karmada-apiserver.
|
||||||
|
The secret must contain the following data keys:
|
||||||
|
- tls.crt: The TLS certificate.
|
||||||
|
- tls.key: The TLS private key.
|
||||||
|
If specified, this CA will be used to issue client certificates for
|
||||||
|
all components that access the APIServer as clients.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name is the name of resource being referenced.
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
description: Namespace is the namespace for the resource being
|
||||||
|
referenced.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
featureGates:
|
featureGates:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
|
@ -113,6 +113,26 @@ type KarmadaSpec struct {
|
||||||
// By default, the operator will only attempt to download the tarball if it's not yet present in the local cache.
|
// By default, the operator will only attempt to download the tarball if it's not yet present in the local cache.
|
||||||
// +optional
|
// +optional
|
||||||
CRDTarball *CRDTarball `json:"crdTarball,omitempty"`
|
CRDTarball *CRDTarball `json:"crdTarball,omitempty"`
|
||||||
|
|
||||||
|
// CustomCertificate specifies the configuration to customize the certificates
|
||||||
|
// for Karmada components or control the certificate generation process, such as
|
||||||
|
// the algorithm, validity period, etc.
|
||||||
|
// Currently, it only supports customizing the CA certificate for limited components.
|
||||||
|
// +optional
|
||||||
|
CustomCertificate *CustomCertificate `json:"customCertificate,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomCertificate holds the configuration for generating the certificate.
|
||||||
|
type CustomCertificate struct {
|
||||||
|
// APIServerCACert references a Kubernetes secret containing the CA certificate
|
||||||
|
// for component karmada-apiserver.
|
||||||
|
// The secret must contain the following data keys:
|
||||||
|
// - tls.crt: The TLS certificate.
|
||||||
|
// - tls.key: The TLS private key.
|
||||||
|
// If specified, this CA will be used to issue client certificates for
|
||||||
|
// all components that access the APIServer as clients.
|
||||||
|
// +optional
|
||||||
|
APIServerCACert *LocalSecretReference `json:"apiServerCACert,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageRegistry represents an image registry as well as the
|
// ImageRegistry represents an image registry as well as the
|
||||||
|
|
|
@ -106,6 +106,27 @@ func (in *CommonSettings) DeepCopy() *CommonSettings {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CustomCertificate) DeepCopyInto(out *CustomCertificate) {
|
||||||
|
*out = *in
|
||||||
|
if in.APIServerCACert != nil {
|
||||||
|
in, out := &in.APIServerCACert, &out.APIServerCACert
|
||||||
|
*out = new(LocalSecretReference)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomCertificate.
|
||||||
|
func (in *CustomCertificate) DeepCopy() *CustomCertificate {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CustomCertificate)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Etcd) DeepCopyInto(out *Etcd) {
|
func (in *Etcd) DeepCopyInto(out *Etcd) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -637,6 +658,11 @@ func (in *KarmadaSpec) DeepCopyInto(out *KarmadaSpec) {
|
||||||
*out = new(CRDTarball)
|
*out = new(CRDTarball)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.CustomCertificate != nil {
|
||||||
|
in, out := &in.CustomCertificate, &out.CustomCertificate
|
||||||
|
*out = new(CustomCertificate)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,25 +212,25 @@ func KarmadaCertEtcdClient() *CertConfig {
|
||||||
// KarmadaCert is karmada certificate, it includes certificate basic message.
|
// KarmadaCert is karmada certificate, it includes certificate basic message.
|
||||||
// we can directly get the byte array of certificate key and cert from the object.
|
// we can directly get the byte array of certificate key and cert from the object.
|
||||||
type KarmadaCert struct {
|
type KarmadaCert struct {
|
||||||
pairName string
|
PairName string
|
||||||
caName string
|
CAName string
|
||||||
cert []byte
|
Cert []byte
|
||||||
key []byte
|
Key []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertData returns certificate cert data.
|
// CertData returns certificate cert data.
|
||||||
func (cert *KarmadaCert) CertData() []byte {
|
func (cert *KarmadaCert) CertData() []byte {
|
||||||
return cert.cert
|
return cert.Cert
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyData returns certificate key data.
|
// KeyData returns certificate key data.
|
||||||
func (cert *KarmadaCert) KeyData() []byte {
|
func (cert *KarmadaCert) KeyData() []byte {
|
||||||
return cert.key
|
return cert.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertName returns cert file name. its default suffix is ".crt".
|
// CertName returns cert file name. its default suffix is ".crt".
|
||||||
func (cert *KarmadaCert) CertName() string {
|
func (cert *KarmadaCert) CertName() string {
|
||||||
pair := cert.pairName
|
pair := cert.PairName
|
||||||
if len(pair) == 0 {
|
if len(pair) == 0 {
|
||||||
pair = "cert"
|
pair = "cert"
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ func (cert *KarmadaCert) CertName() string {
|
||||||
|
|
||||||
// KeyName returns cert key file name. its default suffix is ".key".
|
// KeyName returns cert key file name. its default suffix is ".key".
|
||||||
func (cert *KarmadaCert) KeyName() string {
|
func (cert *KarmadaCert) KeyName() string {
|
||||||
pair := cert.pairName
|
pair := cert.PairName
|
||||||
if len(pair) == 0 {
|
if len(pair) == 0 {
|
||||||
pair = "cert"
|
pair = "cert"
|
||||||
}
|
}
|
||||||
|
@ -282,10 +282,10 @@ func NewCertificateAuthority(cc *CertConfig) (*KarmadaCert, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &KarmadaCert{
|
return &KarmadaCert{
|
||||||
pairName: cc.Name,
|
PairName: cc.Name,
|
||||||
caName: cc.CAName,
|
CAName: cc.CAName,
|
||||||
cert: EncodeCertPEM(cert),
|
Cert: EncodeCertPEM(cert),
|
||||||
key: encoded,
|
Key: encoded,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,10 +329,10 @@ func CreateCertAndKeyFilesWithCA(cc *CertConfig, caCertData, caKeyData []byte) (
|
||||||
}
|
}
|
||||||
|
|
||||||
return &KarmadaCert{
|
return &KarmadaCert{
|
||||||
pairName: cc.Name,
|
PairName: cc.Name,
|
||||||
caName: cc.CAName,
|
CAName: cc.CAName,
|
||||||
cert: EncodeCertPEM(cert),
|
Cert: EncodeCertPEM(cert),
|
||||||
key: encoded,
|
Key: encoded,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -428,23 +428,23 @@ func TestNewCertificateAuthority(t *testing.T) {
|
||||||
t.Fatal("NewCertificateAuthority() returned nil cert")
|
t.Fatal("NewCertificateAuthority() returned nil cert")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert.pairName != cc.Name {
|
if cert.PairName != cc.Name {
|
||||||
t.Errorf("expected pairName to be %s, got %s", cc.Name, cert.pairName)
|
t.Errorf("expected pairName to be %s, got %s", cc.Name, cert.PairName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert.caName != cc.CAName {
|
if cert.CAName != cc.CAName {
|
||||||
t.Errorf("expected caName to be %s, got %s", cc.CAName, cert.caName)
|
t.Errorf("expected caName to be %s, got %s", cc.CAName, cert.CAName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert.cert == nil {
|
if cert.Cert == nil {
|
||||||
t.Error("expected cert to be non-nil")
|
t.Error("expected cert to be non-nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert.key == nil {
|
if cert.Key == nil {
|
||||||
t.Error("expected key to be non-nil")
|
t.Error("expected key to be non-nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
block, _ := pem.Decode(cert.cert)
|
block, _ := pem.Decode(cert.Cert)
|
||||||
if block == nil || block.Type != CertificateBlockType {
|
if block == nil || block.Type != CertificateBlockType {
|
||||||
t.Errorf("expected PEM block type to be %s, got %v", CertificateBlockType, block)
|
t.Errorf("expected PEM block type to be %s, got %v", CertificateBlockType, block)
|
||||||
}
|
}
|
||||||
|
@ -524,19 +524,19 @@ func TestCreateCertAndKeyFilesWithCA(t *testing.T) {
|
||||||
t.Fatal("CreateCertAndKeyFilesWithCA() returned nil cert")
|
t.Fatal("CreateCertAndKeyFilesWithCA() returned nil cert")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert.cert == nil || cert.key == nil {
|
if cert.Cert == nil || cert.Key == nil {
|
||||||
t.Error("Expected cert and key to be non-nil")
|
t.Error("Expected cert and key to be non-nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert.pairName != certConfig.Name {
|
if cert.PairName != certConfig.Name {
|
||||||
t.Errorf("expected pairName to be %s, got %s", certConfig.Name, cert.pairName)
|
t.Errorf("expected pairName to be %s, got %s", certConfig.Name, cert.PairName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cert.caName != certConfig.CAName {
|
if cert.CAName != certConfig.CAName {
|
||||||
t.Errorf("expected caName to be %s, got %s", certConfig.CAName, cert.caName)
|
t.Errorf("expected caName to be %s, got %s", certConfig.CAName, cert.CAName)
|
||||||
}
|
}
|
||||||
|
|
||||||
block, _ := pem.Decode(cert.cert)
|
block, _ := pem.Decode(cert.Cert)
|
||||||
if block == nil || block.Type != CertificateBlockType {
|
if block == nil || block.Type != CertificateBlockType {
|
||||||
t.Errorf("expected PEM block type to be %s, got %v", CertificateBlockType, block)
|
t.Errorf("expected PEM block type to be %s, got %v", CertificateBlockType, block)
|
||||||
}
|
}
|
||||||
|
@ -566,7 +566,7 @@ func TestNewSignedCert_Success(t *testing.T) {
|
||||||
}
|
}
|
||||||
caCert := caCerts[0]
|
caCert := caCerts[0]
|
||||||
|
|
||||||
caKey, err := ParsePrivateKeyPEM(caKarmadaCert.key)
|
caKey, err := ParsePrivateKeyPEM(caKarmadaCert.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,15 +66,15 @@ func NewCertStore() CertStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCert adds a cert to cert store, the cache key is cert pairName by default.
|
// AddCert adds a cert to cert store, the cache key is cert PairName by default.
|
||||||
func (store *KarmadaCertStore) AddCert(cert *KarmadaCert) {
|
func (store *KarmadaCertStore) AddCert(cert *KarmadaCert) {
|
||||||
store.certs[cert.pairName] = cert
|
store.certs[cert.PairName] = cert
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCert get cert from store by cert pairName.
|
// GetCert get cert from store by cert PairName.
|
||||||
func (store *KarmadaCertStore) GetCert(name string) *KarmadaCert {
|
func (store *KarmadaCertStore) GetCert(name string) *KarmadaCert {
|
||||||
for _, c := range store.certs {
|
for _, c := range store.certs {
|
||||||
if c.pairName == name {
|
if c.PairName == name {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,15 +105,15 @@ func (store *KarmadaCertStore) LoadCertFromSecret(secret *corev1.Secret) error {
|
||||||
kc := store.GetCert(pairName)
|
kc := store.GetCert(pairName)
|
||||||
if kc == nil {
|
if kc == nil {
|
||||||
kc = &KarmadaCert{
|
kc = &KarmadaCert{
|
||||||
pairName: pairName,
|
PairName: pairName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(name, certExtension) {
|
if strings.Contains(name, certExtension) {
|
||||||
kc.cert = data
|
kc.Cert = data
|
||||||
}
|
}
|
||||||
if strings.Contains(name, keyExtension) {
|
if strings.Contains(name, keyExtension) {
|
||||||
kc.key = data
|
kc.Key = data
|
||||||
}
|
}
|
||||||
|
|
||||||
store.AddCert(kc)
|
store.AddCert(kc)
|
||||||
|
|
|
@ -22,12 +22,12 @@ import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Helper function to create a new KarmadaCert with given pairName.
|
// Helper function to create a new KarmadaCert with given PairName.
|
||||||
func newKarmadaCert(pairName string, certData, keyData []byte) *KarmadaCert {
|
func newKarmadaCert(pairName string, certData, keyData []byte) *KarmadaCert {
|
||||||
return &KarmadaCert{
|
return &KarmadaCert{
|
||||||
pairName: pairName,
|
PairName: pairName,
|
||||||
cert: certData,
|
Cert: certData,
|
||||||
key: keyData,
|
Key: keyData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,11 +51,11 @@ func TestAddAndGetCert(t *testing.T) {
|
||||||
if retrievedCert == nil {
|
if retrievedCert == nil {
|
||||||
t.Fatalf("expected to retrieve cert but got nil")
|
t.Fatalf("expected to retrieve cert but got nil")
|
||||||
}
|
}
|
||||||
if string(retrievedCert.cert) != "certData" {
|
if string(retrievedCert.Cert) != "certData" {
|
||||||
t.Errorf("expected certData but got %s", string(retrievedCert.cert))
|
t.Errorf("expected certData but got %s", string(retrievedCert.Cert))
|
||||||
}
|
}
|
||||||
if string(retrievedCert.key) != "keyData" {
|
if string(retrievedCert.Key) != "keyData" {
|
||||||
t.Errorf("expected keyData but got %s", string(retrievedCert.key))
|
t.Errorf("expected keyData but got %s", string(retrievedCert.Key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,13 +98,13 @@ func TestLoadCertFromSecret(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cert1 := store.GetCert("cert1")
|
cert1 := store.GetCert("cert1")
|
||||||
if cert1 == nil || string(cert1.cert) != "cert1CertData" || string(cert1.key) != "cert1KeyData" {
|
if cert1 == nil || string(cert1.Cert) != "cert1CertData" || string(cert1.Key) != "cert1KeyData" {
|
||||||
t.Errorf("cert1 content is incorrect expected cert %s key %s, got cert %s key %s", "cert1CertData", "cert1KeyData", string(cert1.cert), string(cert1.key))
|
t.Errorf("cert1 content is incorrect expected cert %s key %s, got cert %s key %s", "cert1CertData", "cert1KeyData", string(cert1.Cert), string(cert1.Key))
|
||||||
}
|
}
|
||||||
|
|
||||||
cert2 := store.GetCert("cert2")
|
cert2 := store.GetCert("cert2")
|
||||||
if cert2 == nil || string(cert2.cert) != "cert2CertData" || string(cert2.key) != "cert2KeyData" {
|
if cert2 == nil || string(cert2.Cert) != "cert2CertData" || string(cert2.Key) != "cert2KeyData" {
|
||||||
t.Errorf("cert2 content is incorrect expected cert %s key %s, got cert %s key %s", "cert2CertData", "cert2KeyData", string(cert2.cert), string(cert2.key))
|
t.Errorf("cert2 content is incorrect expected cert %s key %s, got cert %s key %s", "cert2CertData", "cert2KeyData", string(cert2.Cert), string(cert2.Key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,10 +144,10 @@ func TestLoadCertFromSecret_InvalidFormat(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
karmadaCert := store.GetCert(pairName)
|
karmadaCert := store.GetCert(pairName)
|
||||||
if len(karmadaCert.key) != 0 {
|
if len(karmadaCert.Key) != 0 {
|
||||||
t.Errorf("expected the cert data content to be empty but got %v", karmadaCert.cert)
|
t.Errorf("expected the cert data content to be empty but got %v", karmadaCert.Cert)
|
||||||
}
|
}
|
||||||
if len(karmadaCert.key) != 0 {
|
if len(karmadaCert.Key) != 0 {
|
||||||
t.Errorf("expected the key data content to be empty but got %v", karmadaCert.key)
|
t.Errorf("expected the key data content to be empty but got %v", karmadaCert.Key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,14 @@ var (
|
||||||
|
|
||||||
// InitOptions defines all the init workflow options.
|
// InitOptions defines all the init workflow options.
|
||||||
type InitOptions struct {
|
type InitOptions struct {
|
||||||
Name string
|
Name string
|
||||||
Namespace string
|
Namespace string
|
||||||
Kubeconfig *rest.Config
|
Kubeconfig *rest.Config
|
||||||
KarmadaVersion string
|
KarmadaVersion string
|
||||||
CRDTarball operatorv1alpha1.CRDTarball
|
CRDTarball operatorv1alpha1.CRDTarball
|
||||||
KarmadaDataDir string
|
CustomCertificateConfig operatorv1alpha1.CustomCertificate
|
||||||
Karmada *operatorv1alpha1.Karmada
|
KarmadaDataDir string
|
||||||
|
Karmada *operatorv1alpha1.Karmada
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate is used to validate the initOptions before creating initJob.
|
// Validate is used to validate the initOptions before creating initJob.
|
||||||
|
@ -75,19 +76,20 @@ var _ tasks.InitData = &initData{}
|
||||||
type initData struct {
|
type initData struct {
|
||||||
sync.Once
|
sync.Once
|
||||||
certs.CertStore
|
certs.CertStore
|
||||||
name string
|
name string
|
||||||
namespace string
|
namespace string
|
||||||
karmadaVersion *utilversion.Version
|
karmadaVersion *utilversion.Version
|
||||||
controlplaneConfig *rest.Config
|
controlplaneConfig *rest.Config
|
||||||
controlplaneAddress string
|
controlplaneAddress string
|
||||||
remoteClient clientset.Interface
|
remoteClient clientset.Interface
|
||||||
karmadaClient clientset.Interface
|
karmadaClient clientset.Interface
|
||||||
dnsDomain string
|
dnsDomain string
|
||||||
CRDTarball operatorv1alpha1.CRDTarball
|
CRDTarball operatorv1alpha1.CRDTarball
|
||||||
karmadaDataDir string
|
CustomCertificateConfig operatorv1alpha1.CustomCertificate
|
||||||
privateRegistry string
|
karmadaDataDir string
|
||||||
featureGates map[string]bool
|
privateRegistry string
|
||||||
components *operatorv1alpha1.KarmadaComponents
|
featureGates map[string]bool
|
||||||
|
components *operatorv1alpha1.KarmadaComponents
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInitJob initializes a job with list of init sub-task. and build
|
// NewInitJob initializes a job with list of init sub-task. and build
|
||||||
|
@ -165,18 +167,19 @@ func newRunData(opt *InitOptions) (*initData, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &initData{
|
return &initData{
|
||||||
name: opt.Name,
|
name: opt.Name,
|
||||||
namespace: opt.Namespace,
|
namespace: opt.Namespace,
|
||||||
karmadaVersion: version,
|
karmadaVersion: version,
|
||||||
controlplaneAddress: address,
|
controlplaneAddress: address,
|
||||||
remoteClient: remoteClient,
|
remoteClient: remoteClient,
|
||||||
CRDTarball: opt.CRDTarball,
|
CRDTarball: opt.CRDTarball,
|
||||||
karmadaDataDir: opt.KarmadaDataDir,
|
CustomCertificateConfig: opt.CustomCertificateConfig,
|
||||||
privateRegistry: privateRegistry,
|
karmadaDataDir: opt.KarmadaDataDir,
|
||||||
components: opt.Karmada.Spec.Components,
|
privateRegistry: privateRegistry,
|
||||||
featureGates: opt.Karmada.Spec.FeatureGates,
|
components: opt.Karmada.Spec.Components,
|
||||||
dnsDomain: *opt.Karmada.Spec.HostCluster.Networking.DNSDomain,
|
featureGates: opt.Karmada.Spec.FeatureGates,
|
||||||
CertStore: certs.NewCertStore(),
|
dnsDomain: *opt.Karmada.Spec.HostCluster.Networking.DNSDomain,
|
||||||
|
CertStore: certs.NewCertStore(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,6 +229,10 @@ func (data *initData) CrdTarball() operatorv1alpha1.CRDTarball {
|
||||||
return data.CRDTarball
|
return data.CRDTarball
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (data *initData) CustomCertificate() operatorv1alpha1.CustomCertificate {
|
||||||
|
return data.CustomCertificateConfig
|
||||||
|
}
|
||||||
|
|
||||||
func (data *initData) KarmadaVersion() string {
|
func (data *initData) KarmadaVersion() string {
|
||||||
return data.karmadaVersion.String()
|
return data.karmadaVersion.String()
|
||||||
}
|
}
|
||||||
|
@ -278,6 +285,9 @@ func NewInitOptWithKarmada(karmada *operatorv1alpha1.Karmada) InitOpt {
|
||||||
if karmada.Spec.CRDTarball != nil {
|
if karmada.Spec.CRDTarball != nil {
|
||||||
o.CRDTarball = *karmada.Spec.CRDTarball
|
o.CRDTarball = *karmada.Spec.CRDTarball
|
||||||
}
|
}
|
||||||
|
if karmada.Spec.CustomCertificate != nil {
|
||||||
|
o.CustomCertificateConfig = *karmada.Spec.CustomCertificate
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
operatorv1alpha1 "github.com/karmada-io/karmada/operator/pkg/apis/operator/v1alpha1"
|
||||||
|
"github.com/karmada-io/karmada/operator/pkg/constants"
|
||||||
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
@ -101,6 +104,31 @@ func runCATask(kc *certs.CertConfig) func(d workflow.RunData) error {
|
||||||
if kc.CAName != "" {
|
if kc.CAName != "" {
|
||||||
return fmt.Errorf("this function should only be used for CAs, but cert %s has CA %s", kc.Name, kc.CAName)
|
return fmt.Errorf("this function should only be used for CAs, but cert %s has CA %s", kc.Name, kc.CAName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
customCertConfig := data.CustomCertificate()
|
||||||
|
if kc.Name == constants.CaCertAndKeyName && customCertConfig.APIServerCACert != nil {
|
||||||
|
secretRef := customCertConfig.APIServerCACert
|
||||||
|
klog.V(4).InfoS("[certs] Loading custom CA certificate", "secret", secretRef.Name, "namespace", secretRef.Namespace)
|
||||||
|
|
||||||
|
certData, keyData, err := loadCACertFromSecret(data.RemoteClient(), secretRef)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to load custom CA certificate: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
klog.V(2).InfoS("[certs] Successfully loaded custom CA certificate", "secret", secretRef.Name)
|
||||||
|
|
||||||
|
customKarmadaCert := &certs.KarmadaCert{
|
||||||
|
PairName: kc.Name,
|
||||||
|
CAName: kc.CAName,
|
||||||
|
Cert: certData,
|
||||||
|
Key: keyData,
|
||||||
|
}
|
||||||
|
|
||||||
|
data.AddCert(customKarmadaCert)
|
||||||
|
klog.V(2).InfoS("[certs] Successfully added custom CA certificate to cert store", "certName", kc.Name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
klog.V(4).InfoS("[certs] Creating a new certificate authority", "certName", kc.Name)
|
klog.V(4).InfoS("[certs] Creating a new certificate authority", "certName", kc.Name)
|
||||||
|
|
||||||
cert, err := certs.NewCertificateAuthority(kc)
|
cert, err := certs.NewCertificateAuthority(kc)
|
||||||
|
@ -115,6 +143,22 @@ func runCATask(kc *certs.CertConfig) func(d workflow.RunData) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadCACertFromSecret(client clientset.Interface, ref *operatorv1alpha1.LocalSecretReference) ([]byte, []byte, error) {
|
||||||
|
secret, err := client.CoreV1().Secrets(ref.Namespace).Get(context.TODO(), ref.Name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to retrieve secret %s/%s: %w", ref.Namespace, ref.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
certData := secret.Data[constants.TLSCertDataKey]
|
||||||
|
keyData := secret.Data[constants.TLSPrivateKeyDataKey]
|
||||||
|
|
||||||
|
if len(certData) == 0 || len(keyData) == 0 {
|
||||||
|
return nil, nil, fmt.Errorf("secret %s/%s is missing required keys: %s and %s", ref.Namespace, ref.Name, constants.TLSCertDataKey, constants.TLSPrivateKeyDataKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return certData, keyData, nil
|
||||||
|
}
|
||||||
|
|
||||||
func runCertTask(cc, caCert *certs.CertConfig) func(d workflow.RunData) error {
|
func runCertTask(cc, caCert *certs.CertConfig) func(d workflow.RunData) error {
|
||||||
return func(r workflow.RunData) error {
|
return func(r workflow.RunData) error {
|
||||||
data, ok := r.(InitData)
|
data, ok := r.(InitData)
|
||||||
|
|
|
@ -36,6 +36,7 @@ type InitData interface {
|
||||||
KarmadaClient() clientset.Interface
|
KarmadaClient() clientset.Interface
|
||||||
DataDir() string
|
DataDir() string
|
||||||
CrdTarball() operatorv1alpha1.CRDTarball
|
CrdTarball() operatorv1alpha1.CRDTarball
|
||||||
|
CustomCertificate() operatorv1alpha1.CustomCertificate
|
||||||
KarmadaVersion() string
|
KarmadaVersion() string
|
||||||
Components() *operatorv1alpha1.KarmadaComponents
|
Components() *operatorv1alpha1.KarmadaComponents
|
||||||
FeatureGates() map[string]bool
|
FeatureGates() map[string]bool
|
||||||
|
|
|
@ -46,18 +46,19 @@ func (m *MyTestData) Get() string {
|
||||||
|
|
||||||
// TestInitData contains the configuration and state required to initialize Karmada components.
|
// TestInitData contains the configuration and state required to initialize Karmada components.
|
||||||
type TestInitData struct {
|
type TestInitData struct {
|
||||||
Name string
|
Name string
|
||||||
Namespace string
|
Namespace string
|
||||||
ControlplaneConfigREST *rest.Config
|
ControlplaneConfigREST *rest.Config
|
||||||
DataDirectory string
|
DataDirectory string
|
||||||
CrdTarballArchive operatorv1alpha1.CRDTarball
|
CrdTarballArchive operatorv1alpha1.CRDTarball
|
||||||
KarmadaVersionRelease string
|
CustomCertificateConfig operatorv1alpha1.CustomCertificate
|
||||||
ComponentsUnits *operatorv1alpha1.KarmadaComponents
|
KarmadaVersionRelease string
|
||||||
FeatureGatesOptions map[string]bool
|
ComponentsUnits *operatorv1alpha1.KarmadaComponents
|
||||||
RemoteClientConnector clientset.Interface
|
FeatureGatesOptions map[string]bool
|
||||||
KarmadaClientConnector clientset.Interface
|
RemoteClientConnector clientset.Interface
|
||||||
ControlplaneAddr string
|
KarmadaClientConnector clientset.Interface
|
||||||
Certs []*certs.KarmadaCert
|
ControlplaneAddr string
|
||||||
|
Certs []*certs.KarmadaCert
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure TestInitData implements InitData interface at compile time.
|
// Ensure TestInitData implements InitData interface at compile time.
|
||||||
|
@ -108,6 +109,10 @@ func (t *TestInitData) CrdTarball() operatorv1alpha1.CRDTarball {
|
||||||
return t.CrdTarballArchive
|
return t.CrdTarballArchive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TestInitData) CustomCertificate() operatorv1alpha1.CustomCertificate {
|
||||||
|
return t.CustomCertificateConfig
|
||||||
|
}
|
||||||
|
|
||||||
// KarmadaVersion returns the version of Karmada being used.
|
// KarmadaVersion returns the version of Karmada being used.
|
||||||
func (t *TestInitData) KarmadaVersion() string {
|
func (t *TestInitData) KarmadaVersion() string {
|
||||||
return t.KarmadaVersionRelease
|
return t.KarmadaVersionRelease
|
||||||
|
|
Loading…
Reference in New Issue