github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/initializer/peer/initializer.go (about)

     1  /*
     2   * Copyright contributors to the Hyperledger Fabric Operator project
     3   *
     4   * SPDX-License-Identifier: Apache-2.0
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at:
     9   *
    10   * 	  http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  package initializer
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"os"
    25  	"path/filepath"
    26  
    27  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    28  	commonapi "github.com/IBM-Blockchain/fabric-operator/pkg/apis/common"
    29  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common"
    30  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config"
    31  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/enroller"
    32  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/secretmanager"
    33  	configv1 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/peer/config/v1"
    34  	k8sclient "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient"
    35  	"github.com/pkg/errors"
    36  
    37  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    38  	"k8s.io/apimachinery/pkg/runtime"
    39  
    40  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    41  )
    42  
    43  var log = logf.Log.WithName("peer_initializer")
    44  
    45  type Config struct {
    46  	OUFile                 string
    47  	InterOUFile            string
    48  	CorePeerFile           string
    49  	CorePeerV2File         string
    50  	DeploymentFile         string
    51  	PVCFile                string
    52  	CouchDBPVCFile         string
    53  	ServiceFile            string
    54  	RoleFile               string
    55  	ServiceAccountFile     string
    56  	RoleBindingFile        string
    57  	FluentdConfigMapFile   string
    58  	CouchContainerFile     string
    59  	CouchInitContainerFile string
    60  	IngressFile            string
    61  	Ingressv1beta1File     string
    62  	CCLauncherFile         string
    63  	RouteFile              string
    64  	StoragePath            string
    65  }
    66  
    67  //go:generate counterfeiter -o mocks/ibppeer.go -fake-name IBPPeer . IBPPeer
    68  
    69  type IBPPeer interface {
    70  	DeliveryClientCrypto() map[string][]byte
    71  	OverrideConfig(CoreConfig) error
    72  	GenerateCrypto() (*config.CryptoResponse, error)
    73  	GetConfig() CoreConfig
    74  }
    75  
    76  type PeerConfig interface {
    77  	MergeWith(interface{}, bool) error
    78  	GetAddressOverrides() []configv1.AddressOverride
    79  	ToBytes() ([]byte, error)
    80  	UsingPKCS11() bool
    81  	SetPKCS11Defaults(bool)
    82  	GetBCCSPSection() *commonapi.BCCSP
    83  	GetMaxNameLength() *int
    84  	SetDefaultKeyStore()
    85  }
    86  
    87  type Initializer struct {
    88  	Config        *Config
    89  	Scheme        *runtime.Scheme
    90  	GetLabels     func(instance metav1.Object) map[string]string
    91  	coreConfigMap *CoreConfigMap
    92  	Timeouts      enroller.HSMEnrollJobTimeouts
    93  
    94  	Client        k8sclient.Client
    95  	Validator     common.CryptoValidator
    96  	SecretManager *secretmanager.SecretManager
    97  }
    98  
    99  func New(config *Config, scheme *runtime.Scheme, client k8sclient.Client, labels func(instance metav1.Object) map[string]string, validator common.CryptoValidator, timeouts enroller.HSMEnrollJobTimeouts) *Initializer {
   100  	secretManager := secretmanager.New(client, scheme, labels)
   101  
   102  	return &Initializer{
   103  		Client:        client,
   104  		Config:        config,
   105  		Scheme:        scheme,
   106  		GetLabels:     labels,
   107  		Validator:     validator,
   108  		SecretManager: secretManager,
   109  		coreConfigMap: &CoreConfigMap{Config: config, Scheme: scheme, GetLabels: labels, Client: client},
   110  		Timeouts:      timeouts,
   111  	}
   112  }
   113  
   114  type Response struct {
   115  	Config              CoreConfig
   116  	Crypto              *config.CryptoResponse
   117  	DeliveryClientCerts map[string][]byte
   118  }
   119  
   120  func (i *Initializer) Create(overrides CoreConfig, peer IBPPeer, storagePath string) (*Response, error) {
   121  	var err error
   122  
   123  	err = os.RemoveAll(storagePath)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	err = peer.OverrideConfig(overrides)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	cresp, err := peer.GenerateCrypto()
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	err = os.RemoveAll(storagePath)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	return &Response{
   144  		Config:              peer.GetConfig(),
   145  		DeliveryClientCerts: peer.DeliveryClientCrypto(),
   146  		Crypto:              cresp,
   147  	}, nil
   148  }
   149  
   150  func (i *Initializer) CoreConfigMap() *CoreConfigMap {
   151  	return i.coreConfigMap
   152  }
   153  
   154  func (i *Initializer) Update(overrides CoreConfig, peer IBPPeer) (*Response, error) {
   155  	var err error
   156  
   157  	err = peer.OverrideConfig(overrides)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	return &Response{
   163  		Config:              peer.GetConfig(),
   164  		DeliveryClientCerts: peer.DeliveryClientCrypto(),
   165  	}, nil
   166  }
   167  
   168  func (i *Initializer) GetEnrollers(cryptos *config.Cryptos, instance *current.IBPPeer, storagePath string) error {
   169  	// If no enrollment information provided, don't need to proceed further
   170  	if instance.Spec.Secret == nil || instance.Spec.Secret.Enrollment == nil {
   171  		return nil
   172  	}
   173  
   174  	enrollmentSpec := instance.Spec.Secret.Enrollment
   175  	if enrollmentSpec.Component != nil && cryptos.Enrollment == nil {
   176  		bytes, err := enrollmentSpec.Component.GetCATLSBytes()
   177  		if err != nil {
   178  			return err
   179  		}
   180  
   181  		// Factory will determine if HSM or non-HSM enroller needed and return back appropriate type
   182  		cryptos.Enrollment, err = enroller.Factory(enrollmentSpec.Component, i.Client, instance,
   183  			filepath.Join(storagePath, "ecert"),
   184  			i.Scheme,
   185  			bytes,
   186  			i.Timeouts,
   187  		)
   188  		if err != nil {
   189  			return err
   190  		}
   191  	}
   192  
   193  	// Common enrollers get software based enrollers for TLS and clientauth crypto,
   194  	// these types are not supported for HSM
   195  	err := common.GetCommonEnrollers(cryptos, enrollmentSpec, storagePath)
   196  	if err != nil {
   197  		return err
   198  	}
   199  
   200  	return nil
   201  }
   202  
   203  func (i *Initializer) GetMSPCrypto(cryptos *config.Cryptos, instance *current.IBPPeer) error {
   204  	if instance.Spec.Secret == nil || instance.Spec.Secret.MSP == nil {
   205  		return nil
   206  	}
   207  
   208  	mspSpec := instance.Spec.Secret.MSP
   209  	err := common.GetMSPCrypto(cryptos, mspSpec)
   210  	if err != nil {
   211  		return err
   212  	}
   213  
   214  	return nil
   215  }
   216  
   217  func (i *Initializer) GetInitPeer(instance *current.IBPPeer, storagePath string) (*Peer, error) {
   218  	cryptos := &config.Cryptos{}
   219  
   220  	if instance.Spec.Secret != nil {
   221  		// Prioritize any crypto passed through MSP spec first
   222  		err := i.GetMSPCrypto(cryptos, instance)
   223  		if err != nil {
   224  			return nil, errors.Wrap(err, "failed to populate init peer with MSP spec")
   225  		}
   226  
   227  		err = i.GetEnrollers(cryptos, instance, storagePath)
   228  		if err != nil {
   229  			return nil, errors.Wrap(err, "failed to populate init peer with Enrollment spec")
   230  		}
   231  	}
   232  
   233  	return &Peer{
   234  		Cryptos: cryptos,
   235  	}, nil
   236  }
   237  
   238  func (i *Initializer) GetUpdatedPeer(instance *current.IBPPeer) (*Peer, error) {
   239  	cryptos := &config.Cryptos{}
   240  
   241  	// Only check for any new certs passed through MSP spec
   242  	err := i.GetMSPCrypto(cryptos, instance)
   243  	if err != nil {
   244  		return nil, errors.Wrap(err, "failed to populate updated init peer with MSP spec")
   245  	}
   246  
   247  	return &Peer{
   248  		Cryptos: cryptos,
   249  	}, nil
   250  }
   251  
   252  func (i *Initializer) GenerateSecrets(prefix common.SecretType, instance metav1.Object, crypto *config.Response) error {
   253  	if crypto == nil {
   254  		return nil
   255  	}
   256  	return i.SecretManager.GenerateSecrets(prefix, instance, crypto)
   257  }
   258  
   259  func (i *Initializer) GenerateSecretsFromResponse(instance *current.IBPPeer, cryptoResponse *config.CryptoResponse) error {
   260  	return i.SecretManager.GenerateSecretsFromResponse(instance, cryptoResponse)
   261  }
   262  
   263  func (i *Initializer) UpdateSecrets(prefix common.SecretType, instance *current.IBPPeer, crypto *config.Response) error {
   264  	if crypto == nil {
   265  		return nil
   266  	}
   267  	return i.SecretManager.UpdateSecrets(prefix, instance, crypto)
   268  }
   269  
   270  func (i *Initializer) UpdateSecretsFromResponse(instance *current.IBPPeer, cryptoResponse *config.CryptoResponse) error {
   271  	return i.SecretManager.UpdateSecretsFromResponse(instance, cryptoResponse)
   272  }
   273  
   274  func (i *Initializer) GetCrypto(instance *current.IBPPeer) (*config.CryptoResponse, error) {
   275  	return i.SecretManager.GetCryptoResponseFromSecrets(instance)
   276  }
   277  
   278  func (i *Initializer) GenerateOrdererCACertsSecret(instance *current.IBPPeer, certs map[string][]byte) error {
   279  	secretName := fmt.Sprintf("%s-orderercacerts", instance.GetName())
   280  	err := i.CreateOrUpdateSecret(instance, secretName, certs)
   281  	if err != nil {
   282  		return err
   283  	}
   284  
   285  	return nil
   286  }
   287  
   288  func (i *Initializer) MissingCrypto(instance *current.IBPPeer) bool {
   289  	if instance.IsHSMEnabled() {
   290  		i.Validator.SetHSMEnabled(true)
   291  	}
   292  
   293  	checkClientAuth := instance.ClientAuthCryptoSet()
   294  	err := common.CheckCrypto(i.Validator, instance, checkClientAuth)
   295  	if err != nil {
   296  		log.Info(err.Error())
   297  		return true
   298  	}
   299  
   300  	return false
   301  }
   302  
   303  func (i *Initializer) CheckIfAdminCertsUpdated(instance *current.IBPPeer) (bool, error) {
   304  	current := common.GetAdminCertsFromSecret(i.Client, instance)
   305  	updated := common.GetAdminCertsFromSpec(instance.Spec.Secret)
   306  
   307  	return common.CheckIfCertsDifferent(current, updated)
   308  }
   309  
   310  func (i *Initializer) UpdateAdminSecret(instance *current.IBPPeer) error {
   311  	return i.SecretManager.UpdateAdminCertSecret(instance, instance.Spec.Secret)
   312  }
   313  
   314  func (i *Initializer) CreateOrUpdateSecret(instance *current.IBPPeer, name string, data map[string][]byte) error {
   315  	log.Info(fmt.Sprintf("Creating secret '%s'", name))
   316  
   317  	secret := i.SecretManager.BuildSecret(instance, name, data, i.GetLabels(instance))
   318  	err := i.Client.CreateOrUpdate(context.TODO(), secret, k8sclient.CreateOrUpdateOption{
   319  		Owner:  instance,
   320  		Scheme: i.Scheme,
   321  	})
   322  	if err != nil {
   323  		return err
   324  	}
   325  
   326  	return nil
   327  }