/
kmseditkeypolicy.go
130 lines (114 loc) · 2.89 KB
/
kmseditkeypolicy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package awskms
import (
"context"
"fmt"
"encoding/json"
"errors"
"os"
"os/exec"
"strings"
"github.com/dcoker/biscuit/cmd/internal/shared"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
errNoEditorFound = errors.New("Set your editor preference with VISUAL or EDITOR environment variables.")
errNewPolicyIsZeroBytes = errors.New("No change: the new policy is empty.")
errFileUnchanged = errors.New("No change: the new policy is the same as the existing policy.")
)
type kmsEditKeyPolicy struct {
label *string
regions *[]string
forceRegion *string
}
// NewKmsEditKeyPolicy configures the flags for kmsEditKeyPolicy.
func NewKmsEditKeyPolicy(c *kingpin.CmdClause) shared.Command {
return &kmsEditKeyPolicy{
label: labelFlag(c),
regions: regionsFlag(c),
forceRegion: c.Flag("force-region",
"If set, the key policies will not be checked for consistency between regions and "+
"the editor will open with the policy from the specified region.").String(),
}
}
// Run the command.
func (r *kmsEditKeyPolicy) Run(ctx context.Context) error {
aliasName := kmsAliasName(*r.label)
mrk, err := NewMultiRegionKey(ctx, aliasName, *r.regions, *r.forceRegion)
if err != nil {
return err
}
mrk.Policy, err = prettifyJSON(mrk.Policy)
if err != nil {
return err
}
newPolicy, err := launchEditor(mrk.Policy)
if err != nil {
return err
}
indentedPolicy, err := prettifyJSON(newPolicy)
if err != nil {
return err
}
if err := mrk.SetKeyPolicy(ctx, indentedPolicy); err != nil {
return err
}
fmt.Printf("New policy saved.\n")
return nil
}
func launchEditor(contents string) (string, error) {
f, err := os.CreateTemp("", "secrets")
if err != nil {
return "", err
}
defer os.Remove(f.Name())
if _, err := f.WriteString(contents); err != nil {
return "", err
}
if err := f.Close(); err != nil {
return "", err
}
editor, err := findEditor()
if err != nil {
return "", err
}
cmd := exec.Command(editor, f.Name())
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return "", err
}
bytes, err := os.ReadFile(f.Name())
if err != nil {
return "", err
}
newContents := strings.TrimSpace(string(bytes))
if len(newContents) == 0 {
return "", errNewPolicyIsZeroBytes
}
if newContents == strings.TrimSpace(contents) {
return "", errFileUnchanged
}
return newContents, nil
}
func findEditor() (string, error) {
for _, name := range []string{"VISUAL", "EDITOR"} {
candidate := os.Getenv(name)
if len(candidate) > 0 {
return candidate, nil
}
}
return "", errNoEditorFound
}
func prettifyJSON(content string) (string, error) {
var v interface{}
if err := json.Unmarshal([]byte(content), &v); err != nil {
return "", err
}
indentedPolicyBytes, err := json.MarshalIndent(&v, "", " ")
if err != nil {
return "", err
}
indentedPolicy := string(indentedPolicyBytes)
return indentedPolicy, nil
}