Skip to content
This repository was archived by the owner on Feb 16, 2023. It is now read-only.

Commit 37521a4

Browse files
Add helper commands to assist migration to 1Password Secrets Automation
Add commands to plan and execute a migration of secrets to 1Passsword and a command to assist in using those secrets with the 1Password Kubernetes operator.
1 parent 078f627 commit 37521a4

10 files changed

Lines changed: 1858 additions & 4 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ require (
2323
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf
2424
golang.org/x/text v0.3.2
2525
google.golang.org/api v0.26.0
26-
gopkg.in/yaml.v2 v2.2.2
26+
gopkg.in/yaml.v2 v2.4.0
2727
gotest.tools v2.2.0+incompatible
2828
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,8 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
473473
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
474474
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
475475
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
476+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
477+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
476478
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
477479
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
478480
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

internals/cli/app.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,11 @@ func (c *CommandClause) BindArguments(params []Argument) {
317317
func (c *CommandClause) BindArgumentsArr(param Argument) {
318318
c.Args = []Argument{param}
319319
c.AddPreRunE(func(cmd *cobra.Command, args []string) error {
320-
if err := c.validateArgumentsArrCount(args); err != nil {
321-
return err
320+
if param.Required {
321+
err := c.validateArgumentsArrCount(args)
322+
if err != nil {
323+
return err
324+
}
322325
}
323326
return ArgumentArrRegister(param, args)
324327
})

internals/cli/cobra_template.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,9 @@ var UsageTemplate = `Usage:
397397
{{if .Cmd.Runnable}} {{(useLine .Cmd .Args)}}{{end}}
398398
{{- if .Cmd.HasAvailableSubCommands}} {{ .Cmd.CommandPath}} [command]{{end}}
399399
400-
{{if ne .Cmd.Long ""}}{{ .Cmd.Long | trim }}{{ else }}{{ .Cmd.Short | trim }}{{end}}
400+
{{if ne .Cmd.Long ""}}{{ .Cmd.Short | trim }}
401+
402+
{{ .Cmd.Long | trim }}{{ else }}{{ .Cmd.Short | trim }}{{end}}
401403
{{- if gt (len .Cmd.Aliases) 0}}
402404
403405
Aliases:
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package onepassword
2+
3+
import (
4+
"bytes"
5+
"encoding/base64"
6+
"encoding/json"
7+
"fmt"
8+
"io/ioutil"
9+
"os"
10+
"os/exec"
11+
"path/filepath"
12+
"strings"
13+
14+
"github.com/mitchellh/go-homedir"
15+
)
16+
17+
func CreateVault(name string) error {
18+
_, err := execOP("create", "vault", name)
19+
if err != nil {
20+
return fmt.Errorf("could not create vault '%s': %s", name, err)
21+
}
22+
return nil
23+
}
24+
25+
func CreateItem(vault string, template *ItemTemplate, title string) error {
26+
jsonTemplate, err := json.Marshal(template)
27+
if err != nil {
28+
return err
29+
}
30+
31+
encodedTemplate := base64.RawURLEncoding.EncodeToString(jsonTemplate)
32+
33+
_, err = execOP("create", "item", "login", "--vault="+vault, encodedTemplate, "title="+title)
34+
return err
35+
}
36+
37+
func NewItemTemplate() *ItemTemplate {
38+
return &ItemTemplate{
39+
Sections: []sectionTemplate{
40+
{
41+
Name: "",
42+
Title: "",
43+
},
44+
},
45+
}
46+
}
47+
48+
type ItemTemplate struct {
49+
Sections []sectionTemplate `json:"sections"`
50+
}
51+
52+
type sectionTemplate struct {
53+
Name string `json:"name"`
54+
Title string `json:"title"`
55+
Fields []itemFieldTemplate `json:"fields"`
56+
}
57+
58+
func (tpl *ItemTemplate) AddField(name, value string, concealed bool) {
59+
designation := "concealed"
60+
if !concealed {
61+
designation = "string"
62+
}
63+
64+
tpl.Sections[0].Fields = append(tpl.Sections[0].Fields, itemFieldTemplate{
65+
Designation: designation,
66+
Name: name,
67+
Type: name,
68+
Value: value,
69+
})
70+
}
71+
72+
type itemFieldTemplate struct {
73+
Designation string `json:"k"`
74+
Name string `json:"n"`
75+
Type string `json:"t"`
76+
Value string `json:"v"`
77+
}
78+
79+
func execOP(args ...string) ([]byte, error) {
80+
command := exec.Command("op", args...)
81+
command.Stderr = os.Stderr
82+
var out bytes.Buffer
83+
command.Stdout = &out
84+
85+
err := command.Run()
86+
if err != nil {
87+
return nil, fmt.Errorf("1password: op %s: %s", strings.Join(args, " "), err)
88+
}
89+
90+
return out.Bytes(), nil
91+
}
92+
93+
func EnsureSignedIn() error {
94+
for _, env := range os.Environ() {
95+
if strings.HasPrefix(env, "OP_SESSION") {
96+
return nil
97+
}
98+
}
99+
100+
return fmt.Errorf("OP_SESSION environment variable not found, run `eval $(op signin)` to set one")
101+
}
102+
103+
func GetSignInAddress() (string, error) {
104+
home, err := homedir.Dir()
105+
if err != nil {
106+
return "", err
107+
}
108+
109+
path := filepath.Join(home, ".op", "config")
110+
bytes, err := ioutil.ReadFile(path)
111+
if err != nil {
112+
fmt.Errorf("could not read 1password config file at %s", path)
113+
}
114+
115+
config := struct {
116+
LatestSignin string `json:"latest_signin"`
117+
Accounts []struct {
118+
Shorthand string `json:"shorthand"`
119+
URL string `json:"url"`
120+
} `json:"accounts"`
121+
}{}
122+
123+
err = json.Unmarshal(bytes, &config)
124+
if err != nil {
125+
return "", fmt.Errorf("unexpected format of 1password config file at %s", path)
126+
}
127+
128+
for _, account := range config.Accounts {
129+
if account.Shorthand == config.LatestSignin {
130+
return account.URL, nil
131+
}
132+
}
133+
134+
return "", fmt.Errorf("unexpected format of 1password config file at %s: missing account entry for latest used account", path)
135+
}
136+
137+
func ExistsVault(vaultName string) (bool, error) {
138+
vaultsBytes, err := execOP("list", "vaults")
139+
if err != nil {
140+
return false, fmt.Errorf("could not list vaults: %s", err)
141+
}
142+
143+
vaultsJSON := make([]struct {
144+
UUID string `json:"uuid"`
145+
Name string `json:"name"`
146+
}, 0)
147+
148+
err = json.Unmarshal(vaultsBytes, &vaultsJSON)
149+
if err != nil {
150+
return false, fmt.Errorf("unexpected format of `op list vaults`: %s", vaultsBytes)
151+
}
152+
153+
for _, vault := range vaultsJSON {
154+
if vault.Name == vaultName {
155+
return true, nil
156+
}
157+
}
158+
159+
return false, nil
160+
}
161+
162+
func ExistsItemInVault(vault string, itemName string) (bool, error) {
163+
itemsBytes, err := execOP("list", "items", "--vault", vault)
164+
if err != nil {
165+
return false, fmt.Errorf("could not list items in vault %s: %s", vault, err)
166+
}
167+
168+
itemsJSON := make([]struct {
169+
Overview struct {
170+
Title string `json:"title"`
171+
} `json:"overview"`
172+
}, 0)
173+
174+
err = json.Unmarshal(itemsBytes, &itemsJSON)
175+
if err != nil {
176+
return false, fmt.Errorf("unexpected format of `op list items`: %s", itemsBytes)
177+
}
178+
179+
for _, item := range itemsJSON {
180+
if item.Overview.Title == itemName {
181+
return true, nil
182+
}
183+
}
184+
185+
return false, nil
186+
}

internals/secrethub/app.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ func (app *App) registerCommands() {
151151
NewEnvCommand(app.io, app.clientFactory.NewClient).Register(app.cli)
152152

153153
// Commands
154+
NewMigrateCommand(app.io, app.clientFactory.NewClient).Register(app.cli)
154155
NewInitCommand(app.io, app.clientFactory.NewClientWithCredentials, app.credentialStore).Register(app.cli)
155156
NewSignUpCommand(app.io).Register(app.cli)
156157
NewWriteCommand(app.io, app.clientFactory.NewClient).Register(app.cli)

0 commit comments

Comments
 (0)