github.com/zntrio/harp/v2@v2.0.9/pkg/tasks/container/identity.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package container 19 20 import ( 21 "context" 22 "crypto/rand" 23 "encoding/base64" 24 "encoding/json" 25 "errors" 26 "fmt" 27 28 "github.com/zntrio/harp/v2/build/fips" 29 "github.com/zntrio/harp/v2/pkg/container/identity" 30 "github.com/zntrio/harp/v2/pkg/container/identity/key" 31 "github.com/zntrio/harp/v2/pkg/sdk/types" 32 "github.com/zntrio/harp/v2/pkg/sdk/value" 33 "github.com/zntrio/harp/v2/pkg/tasks" 34 ) 35 36 type IdentityVersion uint 37 38 const ( 39 LegacyIdentity IdentityVersion = 1 40 ModernIdentity IdentityVersion = 2 41 NISTIdentity IdentityVersion = 3 42 ) 43 44 // IdentityTask implements secret container identity creation task. 45 type IdentityTask struct { 46 OutputWriter tasks.WriterProvider 47 Description string 48 Transformer value.Transformer 49 Version IdentityVersion 50 } 51 52 // Run the task. 53 func (t *IdentityTask) Run(ctx context.Context) error { 54 // Check arguments 55 if types.IsNil(t.OutputWriter) { 56 return errors.New("unable to run task with a nil outputWriter provider") 57 } 58 if types.IsNil(t.Transformer) { 59 return errors.New("unable to run task with a nil transformer") 60 } 61 if t.Description == "" { 62 return fmt.Errorf("description must not be blank") 63 } 64 65 // Select appropriate strategy. 66 var generator identity.PrivateKeyGeneratorFunc 67 68 if fips.Enabled() { 69 generator = key.P384 70 } else { 71 switch t.Version { 72 case LegacyIdentity: 73 generator = key.Legacy 74 case ModernIdentity: 75 generator = key.Ed25519 76 case NISTIdentity: 77 generator = key.P384 78 default: 79 return fmt.Errorf("invalid or unsupported identity version '%d'", t.Version) 80 } 81 } 82 83 // Create identity 84 id, payload, err := identity.New(rand.Reader, t.Description, generator) 85 if err != nil { 86 return fmt.Errorf("unable to create a new identity: %w", err) 87 } 88 89 // Encrypt the private key. 90 identityPrivate, err := t.Transformer.To(ctx, payload) 91 if err != nil { 92 return fmt.Errorf("unable to encrypt the private identity key: %w", err) 93 } 94 95 // Assign private key 96 id.Private = &identity.PrivateKey{ 97 Content: base64.RawURLEncoding.EncodeToString(identityPrivate), 98 } 99 100 // Retrieve output writer 101 writer, err := t.OutputWriter(ctx) 102 if err != nil { 103 return fmt.Errorf("unable to retrieve output writer handle: %w", err) 104 } 105 106 // Create identity output 107 if err := json.NewEncoder(writer).Encode(id); err != nil { 108 return fmt.Errorf("unable to serialize final identity: %w", err) 109 } 110 111 // No error 112 return nil 113 }