2024-02-16 08:59:19 -06:00
|
|
|
// Copyright (c) The OpenTofu Authors
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
package encryption_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
2024-06-24 09:18:16 -05:00
|
|
|
"github.com/opentofu/opentofu/internal/configs"
|
2024-02-16 08:59:19 -06:00
|
|
|
"github.com/opentofu/opentofu/internal/encryption"
|
|
|
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
|
|
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
|
|
|
"github.com/opentofu/opentofu/internal/encryption/method/aesgcm"
|
|
|
|
"github.com/opentofu/opentofu/internal/encryption/registry/lockingencryptionregistry"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ConfigA = `
|
2024-03-13 09:58:52 -05:00
|
|
|
state {
|
2024-02-16 08:59:19 -06:00
|
|
|
enforced = true
|
|
|
|
}
|
|
|
|
`
|
|
|
|
ConfigB = `
|
|
|
|
key_provider "static" "basic" {
|
|
|
|
key = "6f6f706830656f67686f6834616872756f3751756165686565796f6f72653169"
|
|
|
|
}
|
|
|
|
method "aes_gcm" "example" {
|
2024-03-07 04:24:37 -06:00
|
|
|
keys = key_provider.static.basic
|
2024-02-16 08:59:19 -06:00
|
|
|
}
|
2024-03-13 09:58:52 -05:00
|
|
|
state {
|
2024-02-16 08:59:19 -06:00
|
|
|
method = method.aes_gcm.example
|
|
|
|
}
|
|
|
|
`
|
|
|
|
)
|
|
|
|
|
|
|
|
// This example demonstrates how to use the encryption package to encrypt and decrypt data.
|
|
|
|
func Example() {
|
|
|
|
// Construct a new registry
|
|
|
|
// the registry is where we store the key providers and methods
|
|
|
|
reg := lockingencryptionregistry.New()
|
|
|
|
if err := reg.RegisterKeyProvider(static.New()); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if err := reg.RegisterMethod(aesgcm.New()); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load the 2 different configurations
|
|
|
|
cfgA, diags := config.LoadConfigFromString("Test Source A", ConfigA)
|
|
|
|
handleDiags(diags)
|
|
|
|
|
|
|
|
cfgB, diags := config.LoadConfigFromString("Test Source B", ConfigB)
|
|
|
|
handleDiags(diags)
|
|
|
|
|
|
|
|
// Merge the configurations
|
|
|
|
cfg := config.MergeConfigs(cfgA, cfgB)
|
|
|
|
|
2024-06-24 09:18:16 -05:00
|
|
|
// Construct static evaluator to pass additional values into encryption configuration.
|
|
|
|
staticEval := configs.NewStaticEvaluator(nil, configs.RootModuleCallForTesting())
|
|
|
|
|
2024-02-16 08:59:19 -06:00
|
|
|
// Construct the encryption object
|
2024-06-24 09:18:16 -05:00
|
|
|
enc, diags := encryption.New(reg, cfg, staticEval)
|
2024-03-04 07:30:30 -06:00
|
|
|
handleDiags(diags)
|
|
|
|
|
2024-03-13 09:58:52 -05:00
|
|
|
sfe := enc.State()
|
2024-03-07 07:55:57 -06:00
|
|
|
|
2024-03-28 10:14:08 -05:00
|
|
|
// Encrypt the data, for this example we will be using the string `{"serial": 42, "lineage": "magic"}`,
|
2024-02-16 08:59:19 -06:00
|
|
|
// but in a real world scenario this would be the plan file.
|
2024-03-28 10:14:08 -05:00
|
|
|
sourceData := []byte(`{"serial": 42, "lineage": "magic"}`)
|
2024-03-04 07:30:30 -06:00
|
|
|
encrypted, err := sfe.EncryptState(sourceData)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2024-02-16 08:59:19 -06:00
|
|
|
|
2024-03-28 10:14:08 -05:00
|
|
|
if string(encrypted) == `{"serial": 42, "lineage": "magic"}` {
|
2024-02-16 08:59:19 -06:00
|
|
|
panic("The data has not been encrypted!")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decrypt
|
2024-03-04 07:30:30 -06:00
|
|
|
decryptedState, err := sfe.DecryptState(encrypted)
|
2024-02-16 08:59:19 -06:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Printf("%s\n", decryptedState)
|
2024-03-28 10:14:08 -05:00
|
|
|
// Output: {"serial": 42, "lineage": "magic"}
|
2024-02-16 08:59:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func handleDiags(diags hcl.Diagnostics) {
|
|
|
|
for _, d := range diags {
|
|
|
|
println(d.Error())
|
|
|
|
}
|
|
|
|
if diags.HasErrors() {
|
|
|
|
panic(diags.Error())
|
|
|
|
}
|
|
|
|
}
|