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  }