github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/initializer/common/config/hsmconfig.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 config 20 21 import ( 22 "context" 23 24 "github.com/pkg/errors" 25 26 corev1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/types" 29 30 "sigs.k8s.io/controller-runtime/pkg/client" 31 logf "sigs.k8s.io/controller-runtime/pkg/log" 32 "sigs.k8s.io/yaml" 33 ) 34 35 var log = logf.Log.WithName("config") 36 37 // Client defines the contract to get resources from clusters 38 type Client interface { 39 Get(ctx context.Context, key client.ObjectKey, obj client.Object) error 40 } 41 42 // ReadHSMConfig reads hsm configuration from 'ibp-hsm-config', and key 'ibp-hsm-config.yaml' 43 // from data 44 func ReadHSMConfig(client Client, instance metav1.Object) (*HSMConfig, error) { 45 // NOTE: This is hard-coded because this name should never be different 46 name := "ibp-hsm-config" 47 48 cm := &corev1.ConfigMap{} 49 err := client.Get( 50 context.TODO(), 51 types.NamespacedName{ 52 Name: name, 53 Namespace: instance.GetNamespace(), 54 }, 55 cm, 56 ) 57 if err != nil { 58 return nil, errors.Wrap(err, "failed to get hsm config 'ibp-hsm-config'") 59 } 60 61 hsmConfig := &HSMConfig{} 62 err = yaml.Unmarshal([]byte(cm.Data["ibp-hsm-config.yaml"]), hsmConfig) 63 if err != nil { 64 return nil, err 65 } 66 67 return hsmConfig, nil 68 } 69 70 // HSMConfig defines the configuration parameters for HSMs 71 type HSMConfig struct { 72 Type string `json:"type,omitempty"` 73 Version string `json:"version,omitempty"` 74 Library Library `json:"library"` 75 MountPaths []MountPath `json:"mountpaths"` 76 Envs []corev1.EnvVar `json:"envs,omitempty"` 77 Daemon *Daemon `json:"daemon,omitempty"` 78 } 79 80 // Library represents the configuration for an HSM library 81 type Library struct { 82 FilePath string `json:"filepath"` 83 Image string `json:"image"` 84 AutoUpdateDisabled bool `json:"autoUpdateDisabled,omitempty"` 85 Auth *Auth `json:"auth,omitempty"` 86 } 87 88 // BuildPullSecret builds the string secret into the type expected by kubernetes 89 func (h *HSMConfig) BuildPullSecret() corev1.LocalObjectReference { 90 if h.Library.Auth != nil { 91 return h.Library.Auth.BuildPullSecret() 92 } 93 return corev1.LocalObjectReference{} 94 } 95 96 // GetVolumes builds the volume spec into the type expected by kubernetes, by default 97 // the volume source is empty dir with memory as the storage medium 98 func (h *HSMConfig) GetVolumes() []corev1.Volume { 99 volumes := []corev1.Volume{} 100 for _, mount := range h.MountPaths { 101 // Skip building volume if using PVC, the PVC is known to the caller of method. 102 // The caller will build the proper PVC volume by setting the appropriate claim name. 103 if !mount.UsePVC { 104 volumes = append(volumes, mount.BuildVolume()) 105 } 106 } 107 return volumes 108 } 109 110 // GetVolumeMounts builds the volume mount spec into the type expected by kubernetes 111 func (h *HSMConfig) GetVolumeMounts() []corev1.VolumeMount { 112 volumeMounts := []corev1.VolumeMount{} 113 for _, mount := range h.MountPaths { 114 // Skip building volume mount if using PVC, the PVC is known to the caller of method. 115 // The caller will build the proper PVC volume mount with the mount path specified 116 // in the HSM config 117 if !mount.UsePVC { 118 volumeMounts = append(volumeMounts, mount.BuildVolumeMount()) 119 } 120 } 121 return volumeMounts 122 } 123 124 // GetEnvs builds the env var spec into the type expected by kubernetes 125 func (h *HSMConfig) GetEnvs() []corev1.EnvVar { 126 return h.Envs 127 } 128 129 // Auth represents the authentication methods that are supported 130 type Auth struct { 131 ImagePullSecret string `json:"imagePullSecret,omitempty"` 132 // UserID string `json:"userid,omitempty"` 133 // Password string `json:"password,omitempty"` 134 } 135 136 // BuildPullSecret builds the pull secret string into the type expected by kubernetes 137 func (a *Auth) BuildPullSecret() corev1.LocalObjectReference { 138 return corev1.LocalObjectReference{Name: a.ImagePullSecret} 139 } 140 141 // MountPath represent the configuration of volume mounts on a container 142 type MountPath struct { 143 Name string `json:"name"` 144 Secret string `json:"secret"` 145 MountPath string `json:"mountpath"` 146 UsePVC bool `json:"usePVC"` 147 SubPath string `json:"subpath,omitempty"` 148 Paths []Path `json:"paths,omitempty"` 149 VolumeSource *corev1.VolumeSource `json:"volumeSource,omitempty"` 150 } 151 152 type Path struct { 153 Key string `json:"key"` 154 Path string `json:"path"` 155 } 156 157 // BuildVolumeMount builds the volume mount spec into the type expected by kubernetes 158 func (m *MountPath) BuildVolumeMount() corev1.VolumeMount { 159 return corev1.VolumeMount{ 160 Name: m.Name, 161 MountPath: m.MountPath, 162 SubPath: m.SubPath, 163 } 164 } 165 166 // BuildVolume builds the volume spec into the type expected by kubernetes 167 func (m *MountPath) BuildVolume() corev1.Volume { 168 // In our initial HSM implementation, we made secrets as the default volume source and only 169 // allowed secrets based volumes. With the introducing of other HSM implementations (opencryptoki), 170 // other volume types had to be introduced and are now directly allowed in the configuration. 171 // However, to not break current users using older config this logic needs to persistent until 172 // we can deprecate older configs. 173 if m.VolumeSource == nil { 174 m.VolumeSource = &corev1.VolumeSource{ 175 Secret: &corev1.SecretVolumeSource{ 176 SecretName: m.Secret, 177 }, 178 } 179 } 180 181 // Setting key/path is only supported for secrets, this is due to the fact 182 // that we made secrets as the default volume source and only allowed secrets based volumes. 183 // For other volume source types, they should configured directly in the hsm config. 184 for _, path := range m.Paths { 185 m.VolumeSource.Secret.Items = append(m.VolumeSource.Secret.Items, 186 corev1.KeyToPath{ 187 Key: path.Key, 188 Path: path.Path, 189 }, 190 ) 191 } 192 193 return corev1.Volume{ 194 Name: m.Name, 195 VolumeSource: *m.VolumeSource, 196 } 197 }