github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/initializer/common/common.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 common
    20  
    21  import (
    22  	"bytes"
    23  	"context"
    24  	"fmt"
    25  	"path/filepath"
    26  
    27  	"github.com/pkg/errors"
    28  
    29  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    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/mspparser"
    33  	"github.com/IBM-Blockchain/fabric-operator/pkg/initializer/validator"
    34  	k8sclient "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/controllerclient"
    35  	"github.com/IBM-Blockchain/fabric-operator/pkg/util"
    36  
    37  	corev1 "k8s.io/api/core/v1"
    38  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    39  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    40  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    41  	"k8s.io/apimachinery/pkg/runtime"
    42  	"k8s.io/apimachinery/pkg/types"
    43  
    44  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    45  )
    46  
    47  var log = logf.Log.WithName("initializer")
    48  
    49  type SecretType string
    50  
    51  var (
    52  	ECERT SecretType = "ecert"
    53  	TLS   SecretType = "tls"
    54  )
    55  
    56  type Instance interface {
    57  	metav1.Object
    58  	runtime.Object
    59  	EnrollerImage() string
    60  	GetPullSecrets() []corev1.LocalObjectReference
    61  	IsHSMEnabled() bool
    62  	UsingHSMProxy() bool
    63  	GetConfigOverride() (interface{}, error)
    64  }
    65  
    66  // NOTE: Modifies cryptos object passed as param
    67  func GetCommonEnrollers(cryptos *config.Cryptos, enrollmentSpec *current.EnrollmentSpec, storagePath string) error {
    68  	if enrollmentSpec.TLS != nil && cryptos.TLS == nil {
    69  		bytes, err := enrollmentSpec.TLS.GetCATLSBytes()
    70  		if err != nil {
    71  			return err
    72  		}
    73  
    74  		caClient := enroller.NewFabCAClient(
    75  			enrollmentSpec.TLS,
    76  			filepath.Join(storagePath, "tls"),
    77  			nil,
    78  			bytes,
    79  		)
    80  		cryptos.TLS = enroller.New(enroller.NewSWEnroller(caClient))
    81  	}
    82  
    83  	if enrollmentSpec.ClientAuth != nil && cryptos.ClientAuth == nil {
    84  		bytes, err := enrollmentSpec.ClientAuth.GetCATLSBytes()
    85  		if err != nil {
    86  			return err
    87  		}
    88  
    89  		caClient := enroller.NewFabCAClient(
    90  			enrollmentSpec.ClientAuth,
    91  			filepath.Join(storagePath, "clientauth"),
    92  			nil,
    93  			bytes,
    94  		)
    95  		cryptos.ClientAuth = enroller.New(enroller.NewSWEnroller(caClient))
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  // NOTE: Modifies cryptos object passed as param
   102  func GetMSPCrypto(cryptos *config.Cryptos, mspSpec *current.MSPSpec) error {
   103  	if mspSpec != nil {
   104  		if mspSpec.Component != nil {
   105  			cryptos.Enrollment = mspparser.New(mspSpec.Component)
   106  		}
   107  
   108  		if mspSpec.TLS != nil {
   109  			cryptos.TLS = mspparser.New(mspSpec.TLS)
   110  		}
   111  
   112  		if mspSpec.ClientAuth != nil {
   113  			cryptos.ClientAuth = mspparser.New(mspSpec.ClientAuth)
   114  		}
   115  	}
   116  
   117  	return nil
   118  }
   119  
   120  //go:generate counterfeiter -o mocks/cryptovalidator.go -fake-name CryptoValidator . CryptoValidator
   121  type CryptoValidator interface {
   122  	CheckEcertCrypto(v1.Object, string) error
   123  	CheckTLSCrypto(v1.Object, string) error
   124  	CheckClientAuthCrypto(v1.Object, string) error
   125  	SetHSMEnabled(bool)
   126  }
   127  
   128  func CheckCrypto(cryptoValidator CryptoValidator, instance v1.Object, checkClientAuth bool) error {
   129  	name := instance.GetName()
   130  
   131  	err := cryptoValidator.CheckEcertCrypto(instance, name)
   132  	if err != nil {
   133  		if validator.CheckError(err) {
   134  			return errors.Wrap(err, "missing ecert crypto")
   135  		}
   136  	}
   137  
   138  	err = cryptoValidator.CheckTLSCrypto(instance, name)
   139  	if err != nil {
   140  		if validator.CheckError(err) {
   141  			log.Info(fmt.Sprintf("missing TLS crypto: %s", err.Error()))
   142  			return errors.Wrap(err, "missing TLS crypto")
   143  		}
   144  	}
   145  
   146  	if checkClientAuth {
   147  		err := cryptoValidator.CheckClientAuthCrypto(instance, name)
   148  		if validator.CheckError(err) {
   149  			log.Info(fmt.Sprintf("missing Client Auth crypto: %s", err.Error()))
   150  			return errors.Wrap(err, "missing Client Auth crypto")
   151  		}
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  func GetAdminCertsFromSecret(client k8sclient.Client, instance v1.Object) map[string][]byte {
   158  	prefix := "ecert-" + instance.GetName()
   159  	namespacedName := types.NamespacedName{
   160  		Name:      prefix + "-admincerts",
   161  		Namespace: instance.GetNamespace(),
   162  	}
   163  
   164  	certs := &corev1.Secret{}
   165  	err := client.Get(context.TODO(), namespacedName, certs)
   166  	if err != nil {
   167  		if !k8serrors.IsNotFound(err) {
   168  			return nil
   169  		}
   170  
   171  		return map[string][]byte{}
   172  	}
   173  
   174  	return certs.Data
   175  }
   176  
   177  func GetAdminCertsFromSpec(spec *current.SecretSpec) []string {
   178  	adminCerts := []string{}
   179  	if spec != nil {
   180  		if spec.MSP != nil {
   181  			if spec.MSP.Component != nil {
   182  				adminCerts = append(adminCerts, spec.MSP.Component.AdminCerts...)
   183  			}
   184  		} else if spec.Enrollment != nil {
   185  			if spec.Enrollment.Component != nil {
   186  				adminCerts = append(adminCerts, spec.Enrollment.Component.AdminCerts...)
   187  			}
   188  		}
   189  	}
   190  
   191  	return adminCerts
   192  }
   193  
   194  // Check for equality between two list of certificates. Order of certificates in the lists
   195  // is ignored, if the two lists contain the same exact certificates this returns true
   196  func CheckIfCertsDifferent(current map[string][]byte, updated []string) (bool, error) {
   197  	// Only detect a difference if the list of updated certificates is not empty
   198  	if len(current) != len(updated) && len(updated) > 0 {
   199  		return true, nil
   200  	}
   201  
   202  	for _, newCert := range updated {
   203  		certFound := false
   204  		newCertBytes, err := util.Base64ToBytes(newCert)
   205  		if err != nil {
   206  			return false, err
   207  		}
   208  
   209  		for _, certBytes := range current {
   210  			if bytes.Equal(certBytes, newCertBytes) {
   211  				certFound = true
   212  				break
   213  			}
   214  		}
   215  
   216  		if !certFound {
   217  			return true, nil
   218  		}
   219  	}
   220  
   221  	return false, nil
   222  }
   223  
   224  func ConvertCertsToBytes(certs []string) ([][]byte, error) {
   225  	certBytes := [][]byte{}
   226  	for _, cert := range certs {
   227  		bytes, err := util.Base64ToBytes(cert)
   228  		if err != nil {
   229  			return nil, err
   230  		}
   231  		certBytes = append(certBytes, bytes)
   232  	}
   233  	return certBytes, nil
   234  }
   235  
   236  func GetConfigFromConfigMap(client k8sclient.Client, instance v1.Object) (*corev1.ConfigMap, error) {
   237  	name := fmt.Sprintf("%s-config", instance.GetName())
   238  	log.Info(fmt.Sprintf("Get config map '%s'...", name))
   239  
   240  	cm := &corev1.ConfigMap{}
   241  	n := types.NamespacedName{
   242  		Name:      name,
   243  		Namespace: instance.GetNamespace(),
   244  	}
   245  
   246  	err := client.Get(context.TODO(), n, cm)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  
   251  	return cm, nil
   252  
   253  }