Introduce DISABLE_INSECURE_FEATURES to disable insecure command executions (#1)

* introduce DISABLE_INSECURE_FEATURES to disable insecure executions

Signed-off-by: Quan TRAN <account@itscaro.me>

* disable remote sources when DISABLE_INSECURE_FEATURES is set to "true"

Signed-off-by: Quan TRAN <account@itscaro.me>

* refactor envvar package

Signed-off-by: Quan TRAN <account@itscaro.me>

* (test) fix test fixtures

Signed-off-by: Quan TRAN <account@itscaro.me>

* use absolute path to avoid unit test failure

Signed-off-by: Quan TRAN <account@itscaro.me>

* Fix conflicts

Co-authored-by: Yusuke Kuoka <ykuoka@gmail.com>
This commit is contained in:
Quan TRAN
2022-06-05 15:15:06 +09:00
committed by GitHub
co-authored by Yusuke Kuoka
parent 789af92c09
commit 577f54af7a
21 changed files with 261 additions and 33 deletions
+32 -1
View File
@@ -8,16 +8,38 @@ import (
"os/exec"
"path/filepath"
"reflect"
"strconv"
"strings"
"text/template"
"github.com/ghodss/yaml"
"github.com/helmfile/helmfile/pkg/envvar"
"github.com/helmfile/helmfile/pkg/helmexec"
"golang.org/x/sync/errgroup"
)
type Values = map[string]interface{}
var DisableInsecureFeaturesErr = DisableInsecureFeaturesError{envvar.DisableInsecureFeatures + " is active, insecure function calls are disabled"}
type DisableInsecureFeaturesError struct {
err string
}
func (e DisableInsecureFeaturesError) Error() string {
return e.err
}
var (
disableInsecureFeatures bool
skipInsecureTemplateFunctions bool
)
func init() {
disableInsecureFeatures, _ = strconv.ParseBool(os.Getenv(envvar.DisableInsecureFeatures))
skipInsecureTemplateFunctions, _ = strconv.ParseBool(os.Getenv(envvar.SkipInsecureTemplateFunctions))
}
func (c *Context) createFuncMap() template.FuncMap {
funcMap := template.FuncMap{
"envExec": c.EnvExec,
@@ -36,7 +58,7 @@ func (c *Context) createFuncMap() template.FuncMap {
"fetchSecretValue": fetchSecretValue,
"expandSecretRefs": fetchSecretValues,
}
if c.preRender {
if c.preRender || skipInsecureTemplateFunctions {
// disable potential side-effect template calls
funcMap["exec"] = func(string, []interface{}, ...string) (string, error) {
return "", nil
@@ -48,6 +70,15 @@ func (c *Context) createFuncMap() template.FuncMap {
return "", nil
}
}
if disableInsecureFeatures {
// disable insecure functions
funcMap["exec"] = func(string, []interface{}, ...string) (string, error) {
return "", DisableInsecureFeaturesErr
}
funcMap["readFile"] = func(string) (string, error) {
return "", DisableInsecureFeaturesErr
}
}
return funcMap
}
+51
View File
@@ -12,6 +12,57 @@ import (
"github.com/stretchr/testify/require"
)
func TestCreateFuncMap(t *testing.T) {
currentVal := disableInsecureFeatures
{
disableInsecureFeatures = false
ctx := &Context{basePath: "."}
funcMaps := ctx.createFuncMap()
args := make([]interface{}, 0)
outputExec, _ := funcMaps["exec"].(func(command string, args []interface{}, inputs ...string) (string, error))("ls", args)
require.Contains(t, outputExec, "context.go")
}
disableInsecureFeatures = currentVal
}
func TestCreateFuncMap_DisabledInsecureFeatures(t *testing.T) {
currentVal := disableInsecureFeatures
{
disableInsecureFeatures = true
ctx := &Context{basePath: "."}
funcMaps := ctx.createFuncMap()
args := make([]interface{}, 0)
_, err1 := funcMaps["exec"].(func(command string, args []interface{}, inputs ...string) (string, error))("ls", args)
require.ErrorIs(t, err1, DisableInsecureFeaturesErr)
_, err2 := funcMaps["readFile"].(func(filename string) (string, error))("context_funcs_test.go")
require.ErrorIs(t, err2, DisableInsecureFeaturesErr)
}
disableInsecureFeatures = currentVal
}
func TestCreateFuncMap_SkipInsecureTemplateFunctions(t *testing.T) {
currentVal := skipInsecureTemplateFunctions
{
skipInsecureTemplateFunctions = true
ctx := &Context{basePath: "."}
funcMaps := ctx.createFuncMap()
args := make([]interface{}, 0)
actual1, err1 := funcMaps["exec"].(func(command string, args []interface{}, inputs ...string) (string, error))("ls", args)
require.Equal(t, "", actual1)
require.ErrorIs(t, err1, nil)
actual2, err2 := funcMaps["readFile"].(func(filename string) (string, error))("context_funcs_test.go")
require.Equal(t, "", actual2)
require.ErrorIs(t, err2, nil)
}
skipInsecureTemplateFunctions = currentVal
}
func TestReadFile(t *testing.T) {
expected := `foo:
bar: BAR