Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions controllers/certs/provision_certs.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
// Package certs provides PKI operations using Fabric CA.
//
// Deprecated: This package is deprecated and will be removed in a future version.
// Use the github.com/kfsoftware/hlf-operator/pkg/pki package instead.
// The new PKI package provides a unified interface for both Fabric CA and HashiCorp Vault.
//
// Migration guide:
//
// Old code:
// crt, key, rootCrt, err := certs.EnrollUser(certs.EnrollUserRequest{...})
//
// New code:
// import "github.com/kfsoftware/hlf-operator/pkg/pki"
// import _ "github.com/kfsoftware/hlf-operator/pkg/pki/fabricca"
//
// provider, _ := pki.NewProvider(&pki.ProviderConfig{
// Type: pki.ProviderTypeFabricCA,
// FabricCA: &pki.FabricCAConfig{...},
// })
// resp, err := provider.Enroll(ctx, pki.EnrollRequest{...})
package certs

import (
Expand Down
21 changes: 21 additions & 0 deletions controllers/certs_vault/provision_certs.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
// Package certs_vault provides PKI operations using HashiCorp Vault.
//
// Deprecated: This package is deprecated and will be removed in a future version.
// Use the github.com/kfsoftware/hlf-operator/pkg/pki package instead.
// The new PKI package provides a unified interface for both Fabric CA and HashiCorp Vault.
//
// Migration guide:
//
// Old code:
// crt, key, rootCrt, err := certs_vault.EnrollUser(clientSet, vaultConf, request, params)
//
// New code:
// import "github.com/kfsoftware/hlf-operator/pkg/pki"
// import _ "github.com/kfsoftware/hlf-operator/pkg/pki/vault"
//
// provider, _ := pki.NewProvider(&pki.ProviderConfig{
// Type: pki.ProviderTypeVault,
// ClientSet: clientSet,
// Vault: &pki.VaultConfig{...},
// })
// resp, err := provider.Enroll(ctx, pki.EnrollRequest{...})
package certs_vault

import (
Expand Down
213 changes: 213 additions & 0 deletions controllers/identity/identity_pki.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package identity

import (
"context"
"crypto/ecdsa"
"crypto/x509"
"encoding/base64"
"fmt"

hlfv1alpha1 "github.com/kfsoftware/hlf-operator/pkg/apis/hlf.kungfusoftware.es/v1alpha1"
"github.com/kfsoftware/hlf-operator/pkg/pki"
"github.com/pkg/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

// pkiHelper provides PKI operations for the identity controller using the unified PKI interface
type pkiHelper struct {
clientSet kubernetes.Interface
}

// newPKIHelper creates a new PKI helper
func newPKIHelper(clientSet kubernetes.Interface) *pkiHelper {
return &pkiHelper{clientSet: clientSet}
}

// createProvider creates the appropriate PKI provider based on credential store configuration
func (h *pkiHelper) createProvider(ctx context.Context, conf *hlfv1alpha1.FabricIdentity) (pki.Provider, error) {
switch conf.Spec.CredentialStore {
case hlfv1alpha1.CredentialStoreVault:
return h.createVaultProvider(ctx, conf)
default:
return h.createFabricCAProvider(ctx, conf)
}
}

// createFabricCAProvider creates a FabricCA PKI provider from identity config
func (h *pkiHelper) createFabricCAProvider(ctx context.Context, conf *hlfv1alpha1.FabricIdentity) (pki.Provider, error) {
cacert, err := h.getCertBytesFromCATLS(conf.Spec.Catls)
if err != nil {
return nil, err
}

caURL := fmt.Sprintf("https://%s:%d", conf.Spec.Cahost, conf.Spec.Caport)

return pki.NewProvider(&pki.ProviderConfig{
Type: pki.ProviderTypeFabricCA,
ClientSet: h.clientSet,
FabricCA: &pki.FabricCAConfig{
URL: caURL,
CAName: conf.Spec.Caname,
TLSCert: string(cacert),
MSPID: conf.Spec.MSPID,
},
})
}

// createVaultProvider creates a Vault PKI provider from identity config
func (h *pkiHelper) createVaultProvider(ctx context.Context, conf *hlfv1alpha1.FabricIdentity) (pki.Provider, error) {
if conf.Spec.Vault == nil {
return nil, errors.New("vault configuration is required for vault credential store")
}

vaultConf := &conf.Spec.Vault.Vault
vaultReq := &conf.Spec.Vault.Request

return pki.NewProvider(&pki.ProviderConfig{
Type: pki.ProviderTypeVault,
ClientSet: h.clientSet,
Vault: &pki.VaultConfig{
URL: vaultConf.URL,
PKIPath: vaultReq.PKI,
Role: vaultReq.Role,
TTL: vaultReq.TTL,
Auth: pki.VaultAuthConfig{
TokenSecretRef: convertSecretRef(vaultConf.TokenSecretRef),
},
TLS: pki.VaultTLSConfig{
CACert: vaultConf.CACert,
ClientCert: vaultConf.ClientCert,
ClientKeySecretRef: convertSecretRef(vaultConf.ClientKeySecretRef),
ServerName: vaultConf.ServerName,
SkipVerify: vaultConf.TLSSkipVerify,
},
},
})
}

// CreateSignCryptoMaterialV2 creates sign crypto material using the PKI interface
func (h *pkiHelper) CreateSignCryptoMaterialV2(
ctx context.Context,
conf *hlfv1alpha1.FabricIdentity,
) (*x509.Certificate, *ecdsa.PrivateKey, *x509.Certificate, error) {
provider, err := h.createProvider(ctx, conf)
if err != nil {
return nil, nil, nil, errors.Wrap(err, "failed to create PKI provider")
}

resp, err := provider.Enroll(ctx, pki.EnrollRequest{
User: conf.Spec.Enrollid,
Secret: conf.Spec.Enrollsecret,
CN: conf.Name,
Hosts: []string{},
MSPID: conf.Spec.MSPID,
Profile: "",
})
if err != nil {
return nil, nil, nil, errors.Wrap(err, "failed to enroll identity")
}

return resp.Certificate, resp.PrivateKey, resp.RootCertificate, nil
}

// ReenrollSignCryptoMaterialV2 re-enrolls sign crypto material using the PKI interface
func (h *pkiHelper) ReenrollSignCryptoMaterialV2(
ctx context.Context,
conf *hlfv1alpha1.FabricIdentity,
existingCert string,
existingKey *ecdsa.PrivateKey,
) (*x509.Certificate, *ecdsa.PrivateKey, *x509.Certificate, error) {
provider, err := h.createProvider(ctx, conf)
if err != nil {
return nil, nil, nil, errors.Wrap(err, "failed to create PKI provider")
}

resp, err := provider.Reenroll(ctx, pki.ReenrollRequest{
EnrollID: conf.Spec.Enrollid,
CN: conf.Name,
Hosts: []string{},
MSPID: conf.Spec.MSPID,
Profile: "",
ExistingCert: existingCert,
ExistingKey: existingKey,
})
if err != nil {
return nil, nil, nil, errors.Wrap(err, "failed to re-enroll identity")
}

return resp.Certificate, existingKey, resp.RootCertificate, nil
}

// RegisterUserV2 registers a user using the PKI interface
func (h *pkiHelper) RegisterUserV2(
ctx context.Context,
conf *hlfv1alpha1.FabricIdentity,
attributes []pki.Attribute,
) (string, error) {
provider, err := h.createProvider(ctx, conf)
if err != nil {
return "", errors.Wrap(err, "failed to create PKI provider")
}

// Check if provider supports registration
if supporter, ok := provider.(pki.RegistrationSupporter); ok {
if !supporter.SupportsRegistration() {
return "", errors.Errorf("provider %s does not support identity registration", provider.Type())
}
}

resp, err := provider.Register(ctx, pki.RegisterRequest{
EnrollID: conf.Spec.Register.Enrollid,
EnrollSecret: conf.Spec.Register.Enrollsecret,
User: conf.Spec.Enrollid,
Secret: conf.Spec.Enrollsecret,
Type: conf.Spec.Register.Type,
MSPID: conf.Spec.MSPID,
Attributes: attributes,
})
if err != nil {
return "", errors.Wrap(err, "failed to register identity")
}

return resp.Secret, nil
}

// getCertBytesFromCATLS retrieves the CA TLS certificate bytes
func (h *pkiHelper) getCertBytesFromCATLS(caTls *hlfv1alpha1.Catls) ([]byte, error) {
var certBytes []byte
var err error

if caTls.Cacert != "" {
certBytes, err = base64.StdEncoding.DecodeString(caTls.Cacert)
if err != nil {
return nil, errors.Wrap(err, "failed to decode CA cert from base64")
}
} else if caTls.SecretRef != nil {
secret, err := h.clientSet.CoreV1().Secrets(caTls.SecretRef.Namespace).Get(
context.Background(),
caTls.SecretRef.Name,
v1.GetOptions{},
)
if err != nil {
return nil, errors.Wrap(err, "failed to get CA cert secret")
}
certBytes = secret.Data[caTls.SecretRef.Key]
} else {
return nil, errors.New("invalid CA TLS configuration: neither cacert nor secretRef provided")
}

return certBytes, nil
}

// convertSecretRef converts from hlfv1alpha1.VaultSecretRef to pki.SecretRef
func convertSecretRef(ref *hlfv1alpha1.VaultSecretRef) *pki.SecretRef {
if ref == nil {
return nil
}
return &pki.SecretRef{
Namespace: ref.Namespace,
Name: ref.Name,
Key: ref.Key,
}
}
32 changes: 20 additions & 12 deletions controllers/ordnode/ordnode_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

// Register PKI providers
_ "github.com/kfsoftware/hlf-operator/pkg/pki/fabricca"
_ "github.com/kfsoftware/hlf-operator/pkg/pki/vault"
)

// FabricOrdererNodeReconciler reconciles a FabricOrdererNode object
Expand Down Expand Up @@ -1087,6 +1091,10 @@ func getConfig(
var tlsKey, adminKey, signKey *ecdsa.PrivateKey
var err error
ctx := context.Background()

// Create PKI helper for certificate operations
pki := newPKIHelper(client)

if tlsParams.External != nil {
secret, err := client.CoreV1().Secrets(tlsParams.External.SecretNamespace).Get(ctx, tlsParams.External.SecretName, v1.GetOptions{})
if err != nil {
Expand All @@ -1109,8 +1117,8 @@ func getConfig(
if err != nil {
return nil, errors.Wrapf(err, "failed to get existing tls crypto material")
}
tlsCert, tlsKey, tlsRootCert, err = ReenrollTLSCryptoMaterial(
client,
tlsCert, tlsKey, tlsRootCert, err = pki.ReenrollTLSCryptoMaterialV2(
ctx,
conf,
&tlsParams,
string(utils.EncodeX509Certificate(tlsCert)),
Expand All @@ -1124,8 +1132,8 @@ func getConfig(
tlsCert, tlsKey, tlsRootCert, err = getExistingTLSCrypto(client, chartName, namespace)
if err != nil {
log.Warnf("Failed to get existing tls crypto material for %s, will create new one", chartName)
tlsCert, tlsKey, tlsRootCert, err = CreateTLSCryptoMaterial(
client,
tlsCert, tlsKey, tlsRootCert, err = pki.CreateTLSCryptoMaterialV2(
ctx,
conf,
&tlsParams,
)
Expand All @@ -1139,8 +1147,8 @@ func getConfig(
if err != nil {
return nil, errors.Wrapf(err, "failed to get existing tls admin crypto material")
}
adminCert, adminKey, adminRootCert, adminClientRootCert, err = ReenrollTLSAdminCryptoMaterial(
client,
adminCert, adminKey, adminRootCert, adminClientRootCert, err = pki.ReenrollTLSAdminCryptoMaterialV2(
ctx,
conf,
&tlsParams,
string(utils.EncodeX509Certificate(adminCert)),
Expand All @@ -1153,8 +1161,8 @@ func getConfig(
adminCert, adminKey, adminRootCert, adminClientRootCert, err = getExistingTLSAdminCrypto(client, chartName, namespace)
if err != nil {
log.Warnf("Failed to get existing tls admin crypto material, creating new one")
adminCert, adminKey, adminRootCert, adminClientRootCert, err = CreateTLSAdminCryptoMaterial(
client,
adminCert, adminKey, adminRootCert, adminClientRootCert, err = pki.CreateTLSAdminCryptoMaterialV2(
ctx,
conf,
&tlsParams,
)
Expand Down Expand Up @@ -1187,8 +1195,8 @@ func getConfig(
return nil, errors.Wrapf(err, "failed to get existing sign crypto material")
}
signCertPem := utils.EncodeX509Certificate(signCert)
signCert, signKey, signRootCert, err = ReenrollSignCryptoMaterial(
client,
signCert, signKey, signRootCert, err = pki.ReenrollSignCryptoMaterialV2(
ctx,
conf,
&signParams,
string(signCertPem),
Expand All @@ -1203,8 +1211,8 @@ func getConfig(
if err != nil {
log.Warnf("Failed to get existing sign crypto material: %s", err)

signCert, signKey, signRootCert, err = CreateSignCryptoMaterial(
client,
signCert, signKey, signRootCert, err = pki.CreateSignCryptoMaterialV2(
ctx,
conf,
&signParams,
)
Expand Down
Loading