mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Integrate encryption config into configs package (#1295)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
parent
2f5dcd5c0a
commit
36eb93f958
@ -3,7 +3,7 @@
|
||||
// Copyright (c) 2023 HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package configs
|
||||
package hcl2shim
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
@ -46,7 +46,7 @@ var _ hcl.Body = mergeBody{}
|
||||
func (b mergeBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
baseSchema := schemaWithDynamic(schema)
|
||||
overrideSchema := schemaWithDynamic(schemaForOverrides(schema))
|
||||
overrideSchema := schemaWithDynamic(SchemaForOverrides(schema))
|
||||
|
||||
baseContent, _, cDiags := b.Base.PartialContent(baseSchema)
|
||||
diags = append(diags, cDiags...)
|
||||
@ -61,7 +61,7 @@ func (b mergeBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagno
|
||||
func (b mergeBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
baseSchema := schemaWithDynamic(schema)
|
||||
overrideSchema := schemaWithDynamic(schemaForOverrides(schema))
|
||||
overrideSchema := schemaWithDynamic(SchemaForOverrides(schema))
|
||||
|
||||
baseContent, baseRemain, cDiags := b.Base.PartialContent(baseSchema)
|
||||
diags = append(diags, cDiags...)
|
@ -3,7 +3,7 @@
|
||||
// Copyright (c) 2023 HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package configs
|
||||
package hcl2shim
|
||||
|
||||
import (
|
||||
"fmt"
|
@ -3,7 +3,7 @@
|
||||
// Copyright (c) 2023 HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package configs
|
||||
package hcl2shim
|
||||
|
||||
import (
|
||||
"testing"
|
@ -3,7 +3,7 @@
|
||||
// Copyright (c) 2023 HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package configs
|
||||
package hcl2shim
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
@ -17,7 +17,7 @@ import (
|
||||
// decoding would've expected a keyword or reference in quotes but our new
|
||||
// decoding expects the keyword or reference to be provided directly as
|
||||
// an identifier-based expression.
|
||||
func exprIsNativeQuotedString(expr hcl.Expression) bool {
|
||||
func ExprIsNativeQuotedString(expr hcl.Expression) bool {
|
||||
_, ok := expr.(*hclsyntax.TemplateExpr)
|
||||
return ok
|
||||
}
|
||||
@ -35,7 +35,7 @@ func exprIsNativeQuotedString(expr hcl.Expression) bool {
|
||||
// Overrides are rarely used, so it's recommended to just create the override
|
||||
// schema on the fly only when it's needed, rather than storing it in a global
|
||||
// variable as we tend to do for a primary schema.
|
||||
func schemaForOverrides(schema *hcl.BodySchema) *hcl.BodySchema {
|
||||
func SchemaForOverrides(schema *hcl.BodySchema) *hcl.BodySchema {
|
||||
ret := &hcl.BodySchema{
|
||||
Attributes: make([]hcl.AttributeSchema, len(schema.Attributes)),
|
||||
Blocks: schema.Blocks,
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||
"github.com/opentofu/opentofu/internal/experiments"
|
||||
|
||||
tfversion "github.com/opentofu/opentofu/version"
|
||||
@ -41,6 +42,7 @@ type Module struct {
|
||||
ProviderRequirements *RequiredProviders
|
||||
ProviderLocalNames map[addrs.Provider]string
|
||||
ProviderMetas map[addrs.Provider]*ProviderMeta
|
||||
Encryption *config.EncryptionConfig
|
||||
|
||||
Variables map[string]*Variable
|
||||
Locals map[string]*Local
|
||||
@ -81,6 +83,7 @@ type File struct {
|
||||
ProviderConfigs []*Provider
|
||||
ProviderMetas []*ProviderMeta
|
||||
RequiredProviders []*RequiredProviders
|
||||
Encryptions []*config.EncryptionConfig
|
||||
|
||||
Variables []*Variable
|
||||
Locals []*Local
|
||||
@ -280,6 +283,19 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
|
||||
m.ProviderMetas[provider] = pm
|
||||
}
|
||||
|
||||
for _, e := range file.Encryptions {
|
||||
if m.Encryption != nil {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate encryption configuration",
|
||||
Detail: fmt.Sprintf("A module may have only one encryption configuration. Encryption was previously configured at %s.", m.Encryption.DeclRange),
|
||||
Subject: &e.DeclRange,
|
||||
})
|
||||
continue
|
||||
}
|
||||
m.Encryption = e
|
||||
}
|
||||
|
||||
for _, v := range file.Variables {
|
||||
if existing, exists := m.Variables[v.Name]; exists {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
@ -552,6 +568,22 @@ func (m *Module) mergeFile(file *File) hcl.Diagnostics {
|
||||
}
|
||||
}
|
||||
|
||||
if len(file.Encryptions) != 0 {
|
||||
switch len(file.Encryptions) {
|
||||
case 1:
|
||||
m.Encryption = m.Encryption.Merge(file.Encryptions[0])
|
||||
default:
|
||||
// An override file with multiple encryptions is still invalid, even
|
||||
// though it can override encryptions from _other_ files.
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate encryption configuration",
|
||||
Detail: fmt.Sprintf("Each override file may have only one encryption configuration. Encryption was previously configured at %s.", file.Encryptions[0].DeclRange),
|
||||
Subject: &file.Encryptions[1].DeclRange,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range file.Variables {
|
||||
existing, exists := m.Variables[v.Name]
|
||||
if !exists {
|
||||
|
@ -7,6 +7,7 @@ package configs
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||
)
|
||||
|
||||
// LoadConfigFile reads the file at the given path and parses it as a config
|
||||
@ -111,6 +112,13 @@ func (p *Parser) loadConfigFile(path string, override bool) (*File, hcl.Diagnost
|
||||
file.ProviderMetas = append(file.ProviderMetas, providerCfg)
|
||||
}
|
||||
|
||||
case "encryption":
|
||||
encryptionCfg, cfgDiags := config.DecodeConfig(innerBlock.Body, innerBlock.DefRange)
|
||||
diags = append(diags, cfgDiags...)
|
||||
if encryptionCfg != nil {
|
||||
file.Encryptions = append(file.Encryptions, encryptionCfg)
|
||||
}
|
||||
|
||||
default:
|
||||
// Should never happen because the above cases should be exhaustive
|
||||
// for all block type names in our schema.
|
||||
|
25
internal/configs/shim.go
Normal file
25
internal/configs/shim.go
Normal file
@ -0,0 +1,25 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/opentofu/opentofu/internal/configs/hcl2shim"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// These were all moved to the hcl2shim package, but still have uses referenced from this package
|
||||
// TODO Call sites through opentofu to these functions should be migrated to hcl2shim eventually and this file removed
|
||||
func MergeBodies(base, override hcl.Body) hcl.Body {
|
||||
return hcl2shim.MergeBodies(base, override)
|
||||
}
|
||||
|
||||
func exprIsNativeQuotedString(expr hcl.Expression) bool {
|
||||
return hcl2shim.ExprIsNativeQuotedString(expr)
|
||||
}
|
||||
|
||||
func schemaForOverrides(schema *hcl.BodySchema) *hcl.BodySchema {
|
||||
return hcl2shim.SchemaForOverrides(schema)
|
||||
}
|
||||
|
||||
func SynthBody(filename string, values map[string]cty.Value) hcl.Body {
|
||||
return hcl2shim.SynthBody(filename, values)
|
||||
}
|
@ -11,9 +11,9 @@ import (
|
||||
"github.com/opentofu/opentofu/internal/encryption/method"
|
||||
)
|
||||
|
||||
// Config describes the terraform.encryption HCL block you can use to configure the state and plan encryption.
|
||||
// EncryptionConfig describes the terraform.encryption HCL block you can use to configure the state and plan encryption.
|
||||
// The individual fields of this struct match the HCL structure directly.
|
||||
type Config struct {
|
||||
type EncryptionConfig struct {
|
||||
KeyProviderConfigs []KeyProviderConfig `hcl:"key_provider,block"`
|
||||
MethodConfigs []MethodConfig `hcl:"method,block"`
|
||||
|
||||
@ -21,11 +21,14 @@ type Config struct {
|
||||
StateFile *EnforcableTargetConfig `hcl:"statefile,block"`
|
||||
PlanFile *EnforcableTargetConfig `hcl:"planfile,block"`
|
||||
Remote *RemoteConfig `hcl:"remote_data_source,block"`
|
||||
|
||||
// Not preserved through merge operations
|
||||
DeclRange hcl.Range
|
||||
}
|
||||
|
||||
// Merge returns a merged configuration with the current config and the specified override combined, the override
|
||||
// taking precedence.
|
||||
func (c *Config) Merge(override *Config) *Config {
|
||||
func (c *EncryptionConfig) Merge(override *EncryptionConfig) *EncryptionConfig {
|
||||
return MergeConfigs(c, override)
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
// This method serves as an example for how someone using this library might want to load a configuration.
|
||||
// if they were not using gohcl directly.
|
||||
// However! Right now, this method should only be used in tests, as OpenTofu should be using gohcl to parse the configuration.
|
||||
func LoadConfigFromString(sourceName string, rawInput string) (*Config, hcl.Diagnostics) {
|
||||
func LoadConfigFromString(sourceName string, rawInput string) (*EncryptionConfig, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
var file *hcl.File
|
||||
|
||||
|
@ -7,12 +7,18 @@ package config
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/configs/hcl2shim"
|
||||
)
|
||||
|
||||
// MergeConfigs merges two Configs together, with the override taking precedence.
|
||||
func MergeConfigs(cfg *Config, override *Config) *Config {
|
||||
return &Config{
|
||||
func MergeConfigs(cfg *EncryptionConfig, override *EncryptionConfig) *EncryptionConfig {
|
||||
if cfg == nil {
|
||||
return override
|
||||
}
|
||||
if override == nil {
|
||||
return cfg
|
||||
}
|
||||
return &EncryptionConfig{
|
||||
KeyProviderConfigs: mergeKeyProviderConfigs(cfg.KeyProviderConfigs, override.KeyProviderConfigs),
|
||||
MethodConfigs: mergeMethodConfigs(cfg.MethodConfigs, override.MethodConfigs),
|
||||
|
||||
@ -162,5 +168,5 @@ func mergeBody(base hcl.Body, override hcl.Body) hcl.Body {
|
||||
return base
|
||||
}
|
||||
|
||||
return configs.MergeBodies(base, override)
|
||||
return hcl2shim.MergeBodies(base, override)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hcltest"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/configs/hcl2shim"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
@ -21,7 +21,7 @@ func TestMergeMethodConfigs(t *testing.T) {
|
||||
return MethodConfig{
|
||||
Type: typeName,
|
||||
Name: name,
|
||||
Body: configs.SynthBody("method", map[string]cty.Value{
|
||||
Body: hcl2shim.SynthBody("method", map[string]cty.Value{
|
||||
key: cty.StringVal(value),
|
||||
}),
|
||||
}
|
||||
@ -132,7 +132,7 @@ func TestMergeKeyProviderConfigs(t *testing.T) {
|
||||
return KeyProviderConfig{
|
||||
Type: typeName,
|
||||
Name: name,
|
||||
Body: configs.SynthBody("key_provider", map[string]cty.Value{
|
||||
Body: hcl2shim.SynthBody("key_provider", map[string]cty.Value{
|
||||
key: cty.StringVal(value),
|
||||
}),
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ import (
|
||||
// This method is here as an example for how someone using this library might want to decode a configuration.
|
||||
// if they were not using gohcl directly.
|
||||
// Right now for real world use this is only intended to be used in tests, until we publish this publicly.
|
||||
func DecodeConfig(body hcl.Body, rng hcl.Range) (*Config, hcl.Diagnostics) {
|
||||
cfg := &Config{}
|
||||
func DecodeConfig(body hcl.Body, rng hcl.Range) (*EncryptionConfig, hcl.Diagnostics) {
|
||||
cfg := &EncryptionConfig{DeclRange: rng}
|
||||
|
||||
diags := gohcl.DecodeBody(body, nil, cfg)
|
||||
if diags.HasErrors() {
|
||||
|
@ -30,12 +30,12 @@ type Encryption interface {
|
||||
|
||||
type encryption struct {
|
||||
// Inputs
|
||||
cfg *config.Config
|
||||
cfg *config.EncryptionConfig
|
||||
reg registry.Registry
|
||||
}
|
||||
|
||||
// New creates a new Encryption provider from the given configuration and registry.
|
||||
func New(reg registry.Registry, cfg *config.Config) Encryption {
|
||||
func New(reg registry.Registry, cfg *config.EncryptionConfig) Encryption {
|
||||
return &encryption{
|
||||
cfg: cfg,
|
||||
reg: reg,
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
type targetBuilder struct {
|
||||
cfg *config.Config
|
||||
cfg *config.EncryptionConfig
|
||||
reg registry.Registry
|
||||
|
||||
// Used to evaluate hcl expressions
|
||||
|
Loading…
Reference in New Issue
Block a user