Skip to content

Commit

Permalink
Fix flaky verify command
Browse files Browse the repository at this point in the history
  • Loading branch information
dschniepp committed May 13, 2020
1 parent b660699 commit 5577562
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 35 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Renamed cert source `controller` to `kubernetes`
- Moved `maxAge` one level up
### Fixed
- Flaky verify command

## [0.2.1] - 2020-05-11
### Changed
Expand Down
21 changes: 12 additions & 9 deletions cmd/sealit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ func main() {
Aliases: []string{"i"},
Usage: "create a config file in the current dir",
Action: func(c *cli.Context) (err error) {
err = internal.Init(c.String("config"), c.Bool("force"))
return err
return internal.Init(c.String("config"), c.Bool("force"))
},
Flags: []cli.Flag{
&cli.BoolFlag{
Expand All @@ -40,8 +39,11 @@ func main() {
Usage: "seal all secrets",
Action: func(c *cli.Context) (err error) {
sealit, err := internal.New(c.String("config"), c.String("kubeconfig"), c.Bool("fetch-cert"))
err = sealit.Seal(c.Bool("force"))
return err
if err != nil {
return err
}

return sealit.Seal(c.Bool("force"))
},
Flags: []cli.Flag{
&cli.BoolFlag{
Expand All @@ -62,8 +64,10 @@ func main() {
Usage: "verify if all secrets are encrypted",
Action: func(c *cli.Context) (err error) {
sealit, err := internal.New(c.String("config"), c.String("kubeconfig"), c.Bool("fetch-cert"))
err = sealit.Verify()
return err
if err != nil {
return err
}
return sealit.Verify()
},
Flags: []cli.Flag{
&cli.BoolFlag{
Expand All @@ -77,9 +81,8 @@ func main() {
Name: "template",
Aliases: []string{"t"},
Usage: "create a sealed secrets template",
Action: func(c *cli.Context) (err error) {
err = internal.Template(c.String("file"))
return err
Action: func(c *cli.Context) error {
return internal.Template(c.String("file"))
},
Flags: []cli.Flag{
&cli.StringFlag{
Expand Down
4 changes: 3 additions & 1 deletion example/values.dev.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
env:
password: secret!
username: john
username: john
secret: john
asd_username: john
12 changes: 9 additions & 3 deletions internal/sealer.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,14 @@ func NewSealer(srs *SealingRuleSet, m *Metadata, fetchCert bool) (s *Sealer, err
}, nil
}

func (s *Sealer) seal(key *yaml.Node, value *yaml.Node) error {
func (s *Sealer) Verify(key *yaml.Node, value *yaml.Node) error {
if s.regexp.MatchString(key.Value) && !strings.HasPrefix(value.Value, "ENC:") {
return fmt.Errorf("key `%s` is not encrypted", key.Value)
}
return nil
}

func (s *Sealer) Seal(key *yaml.Node, value *yaml.Node) error {
if s.regexp.MatchString(key.Value) {
if !strings.HasPrefix(value.Value, "ENC:") {
ciphertext, err := crypto.HybridEncrypt(rand.Reader, s.publicKey, []byte(value.Value), s.label)
Expand All @@ -97,8 +104,7 @@ func (s *Sealer) seal(key *yaml.Node, value *yaml.Node) error {
encodedSecret := base64.StdEncoding.EncodeToString(ciphertext)
value.SetString(fmt.Sprintf("ENC:%s", encodedSecret))
s.metadata.SealedAt = time.Now().Format(time.RFC3339)

log.Printf("[INFO] Encrypted value of `%s`", key.Value)
log.Printf("[DEBUG] Encrypted value of `%s`", key.Value)

return nil
}
Expand Down
42 changes: 39 additions & 3 deletions internal/sealer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,49 @@ func TestSealSecrets(t *testing.T) {

k := &yaml.Node{Value: "test_password"}
v := &yaml.Node{Value: "secret!"}
s.seal(k, v)
s.Seal(k, v)

if strings.Contains(v.Value, "secret!") && !strings.HasPrefix(v.Value, "ENC:") {
t.Errorf("Sealing was unsuccessful, got: %s, which contains: %s or no ENC indicator.", v.Value, "secret!")
}
}

func TestVerifySecrets(t *testing.T) {
key, _ := testGeneratePrivateKey()

s := Sealer{
regexp: regexp.MustCompile(`(password|pin)$`),
publicKey: &key.PublicKey,
metadata: &Metadata{},
}

k := &yaml.Node{Value: "test_password"}
v := &yaml.Node{Value: "ENC:secret!"}
err := s.Verify(k, v)

if err != nil {
t.Errorf("Verify was unsuccessful, got an error %s.", err.Error())
}
}

func TestVerifyUnsealedSecrets(t *testing.T) {
key, _ := testGeneratePrivateKey()

s := Sealer{
regexp: regexp.MustCompile(`(password|pin)$`),
publicKey: &key.PublicKey,
metadata: &Metadata{},
}

k := &yaml.Node{Value: "test_password"}
v := &yaml.Node{Value: "secret!"}
err := s.Verify(k, v)

if err == nil {
t.Errorf("Verify was unsuccessful, got no error due to unsealed secret.")
}
}

func TestSealingOfAlreadySealedSecrets(t *testing.T) {
key, _ := testGeneratePrivateKey()

Expand All @@ -42,7 +78,7 @@ func TestSealingOfAlreadySealedSecrets(t *testing.T) {

k := &yaml.Node{Value: "test_password"}
v := &yaml.Node{Value: "ENC:secret!"}
s.seal(k, v)
s.Seal(k, v)

if v.Value != "ENC:secret!" {
t.Errorf("Sealing sealed again, got: %s, want: %s.", v.Value, "ENC:secret!")
Expand All @@ -60,7 +96,7 @@ func TestSealNonSecrets(t *testing.T) {

k := &yaml.Node{Value: "test"}
v := &yaml.Node{Value: "secret!"}
s.seal(k, v)
s.Seal(k, v)

if v.Value != "secret!" {
t.Errorf("Sealed yaml was incorrect, got: %s, want: %s.", v.Value, "secret!")
Expand Down
35 changes: 23 additions & 12 deletions internal/sealit.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func New(sealitconfig string, kubeconfig string, fetchCert bool) (*Sealit, error
configFile, err := ioutil.ReadFile(sealitconfig)

if err != nil {
fmt.Printf("[ERROR] %v\n", err)
return nil, err
}

config, err := LoadConfig(configFile, kubeconfig)
Expand Down Expand Up @@ -109,7 +109,12 @@ func (s *Sealit) Seal(force bool) (err error) {
}

log.Print("[DEBUG] Apply sealing function")
vf.ApplyFuncToValues(sealer.seal)
err = vf.ApplyFuncToValues(sealer.Seal)
if err != nil {
return err
}

log.Print("[DEBUG] Export sealed yaml.Node tree")
data, err = vf.Export()
if err != nil {
return err
Expand All @@ -120,13 +125,13 @@ func (s *Sealit) Seal(force bool) (err error) {
}

func (s *Sealit) Verify() (err error) {
return s.applyToEveryMatchingFile(func(srs *SealingRuleSet, f os.FileInfo) (err error) {
data, err := ioutil.ReadFile(f.Name())
return s.applyToEveryMatchingFile(func(srs *SealingRuleSet, fi os.FileInfo) (err error) {
data, err := ioutil.ReadFile(fi.Name())
if err != nil {
return err
}

log.Printf("[DEBUG] Load values file %s", f.Name())
log.Printf("[DEBUG] Load values file %s", fi.Name())
vf, err := NewValueFile(data)
if err != nil {
return err
Expand All @@ -139,29 +144,35 @@ func (s *Sealit) Verify() (err error) {
}

log.Print("[DEBUG] Apply sealing function")
vf.ApplyFuncToValues(sealer.seal)
log.Print("[DEBUG] Check of sealing date was refreshed")
if vf.Metadata == nil || vf.Metadata.SealedAt != sealer.metadata.SealedAt {
return fmt.Errorf("%s is not completely encrypted", f.Name())
err = vf.ApplyFuncToValues(sealer.Verify)

if err != nil {
return fmt.Errorf("in file %s %s", fi.Name(), err.Error())
}

return err
})
}

func (s *Sealit) applyToEveryMatchingFile(fun func(*SealingRuleSet, os.FileInfo) error) (err error) {
func (s *Sealit) applyToEveryMatchingFile(fun func(*SealingRuleSet, os.FileInfo) error) error {
files, err := ioutil.ReadDir(".")

if err != nil {
return err
}

for _, f := range files {
if !f.IsDir() {
for _, srs := range s.config.SealingRuleSets {
fileNamePattern := regexp.MustCompile(srs.FileRegex)
if fileNamePattern.MatchString(f.Name()) {
err = fun(&srs, f)
if err := fun(&srs, f); err != nil {
return err
}
}
}
}
}

return err
return nil
}
23 changes: 16 additions & 7 deletions internal/values_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,32 +49,41 @@ func NewValueFile(d []byte) (*File, error) {
return &f, nil
}

func (f *File) ApplyFuncToValues(manipulator func(*yaml.Node, *yaml.Node) error) {
func (f *File) ApplyFuncToValues(manipulator func(*yaml.Node, *yaml.Node) error) error {
log.Printf("[DEBUG] Apply manipulation function to values tree")
walkAndApplyFunc(f.values.Content[0], manipulator)
return walkAndApplyFunc(f.values.Content[0], manipulator)
}

func walkAndApplyFunc(node *yaml.Node, manipulator func(*yaml.Node, *yaml.Node) error) {
func walkAndApplyFunc(node *yaml.Node, manipulator func(*yaml.Node, *yaml.Node) error) (err error) {
for i := 0; i < len(node.Content); i = i + 2 {
key := node.Content[i]
value := node.Content[i+1]
// Only walk through non sealit elements
if key.Value != sealitYamlKey {
if value.Kind == yaml.ScalarNode {
manipulator(key, value)
if err := manipulator(key, value); err != nil {
return err
}
} else if value.Kind == yaml.SequenceNode {
for _, childNode := range value.Content {
if childNode.Kind == yaml.ScalarNode {
manipulator(key, childNode)
if err := manipulator(key, childNode); err != nil {
return err
}
} else {
walkAndApplyFunc(childNode, manipulator)
if err := walkAndApplyFunc(childNode, manipulator); err != nil {
return err
}
}
}
} else {
walkAndApplyFunc(value, manipulator)
if err := walkAndApplyFunc(value, manipulator); err != nil {
return err
}
}
}
}
return nil
}

func (f *File) Export() ([]byte, error) {
Expand Down

0 comments on commit 5577562

Please sign in to comment.