Updated to op v2

Signed-off-by: Marcus Noble <github@marcusnoble.co.uk>
This commit is contained in:
Marcus Noble 2024-09-28 09:40:41 +01:00
parent 4f0fb2a170
commit bb4f2232db
Signed by: AverageMarcus
GPG Key ID: B8F2DB8A7AEBAF78
6 changed files with 26 additions and 96 deletions

View File

@ -8,9 +8,11 @@ RUN go mod download
ADD . . ADD . .
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" -o kube-1password-secrets main.go RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" -o kube-1password-secrets main.go
FROM 1password/op:2 as OP
FROM golang:1.14-alpine FROM golang:1.14-alpine
WORKDIR /app/ WORKDIR /app/
COPY --from=builder /usr/local/bin/op /usr/local/bin/op COPY --from=op /usr/local/bin/op /usr/local/bin/op
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /etc/passwd /etc/passwd COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /app/kube-1password-secrets /app/kube-1password-secrets COPY --from=builder /app/kube-1password-secrets /app/kube-1password-secrets

View File

@ -3,20 +3,11 @@ package onepassword
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"log"
"os/exec" "os/exec"
"strings"
) )
// Client is the 1Password client // Client is the 1Password client
type Client struct { type Client struct{}
Domain string
Email string
Password string
SecretKey string
Session string
}
// Secret contains the credentials from a 1Password secret // Secret contains the credentials from a 1Password secret
type Secret struct { type Secret struct {
@ -28,13 +19,8 @@ type Secret struct {
} }
// New authenticates with the provided values and returns a new 1Password client // New authenticates with the provided values and returns a new 1Password client
func New(domain string, email string, password string, secretKey string) (*Client, error) { func New() (*Client, error) {
client := &Client{ client := &Client{}
Domain: domain,
Email: email,
Password: password,
SecretKey: secretKey,
}
if err := client.authenticate(); err != nil { if err := client.authenticate(); err != nil {
return nil, err return nil, err
} }
@ -42,27 +28,16 @@ func New(domain string, email string, password string, secretKey string) (*Clien
} }
func (op *Client) authenticate() error { func (op *Client) authenticate() error {
cmd := exec.Command("op", "signin", op.Domain, op.Email, op.SecretKey, "--output=raw") cmd := exec.Command("op", "user", "get", "--me")
stdin, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("Cannot attach to stdin: %s", err)
}
go func() {
defer stdin.Close()
if _, err := io.WriteString(stdin, fmt.Sprintf("%s\n", op.Password)); err != nil {
log.Println("[Error]", err)
}
}()
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("Cannot signin: %s\n%s", err, output) return fmt.Errorf("Cannot verify auth: %s\n%s", err, output)
} }
op.Session = strings.Trim(string(output), "\n")
return nil return nil
} }
func (op Client) runCmd(args ...string) ([]byte, error) { func (op Client) runCmd(args ...string) ([]byte, error) {
args = append(args, fmt.Sprintf("--session=%s", op.Session)) args = append(args, "--format=json")
cmd := exec.Command("op", args...) cmd := exec.Command("op", args...)
res, err := cmd.CombinedOutput() res, err := cmd.CombinedOutput()
if err != nil { if err != nil {
@ -73,7 +48,7 @@ func (op Client) runCmd(args ...string) ([]byte, error) {
// GetSecret returns the values from the secret stored in 1Password with a UUID matching the secretID // GetSecret returns the values from the secret stored in 1Password with a UUID matching the secretID
func (op *Client) GetSecret(vault, secretID string) (*Secret, error) { func (op *Client) GetSecret(vault, secretID string) (*Secret, error) {
res, err := op.runCmd("get", "item", secretID, fmt.Sprintf("--vault=%s", vault)) res, err := op.runCmd("item", "get", secretID, "--reveal", fmt.Sprintf("--vault=%s", vault))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -84,30 +59,24 @@ func (op *Client) GetSecret(vault, secretID string) (*Secret, error) {
secret := &Secret{ secret := &Secret{
ID: item.UUID, ID: item.UUID,
Title: item.Overview.Title, Title: item.Title,
Username: "", Username: "",
Password: "", Password: "",
SecretText: "", SecretText: "",
} }
if len(item.Details.Fields) > 0 { if len(item.Fields) > 0 {
for _, field := range item.Details.Fields { for _, field := range item.Fields {
switch field.Name { switch field.Name {
case "username": case "username":
secret.Username = field.Value secret.Username = field.Value
case "password": case "password":
secret.Password = field.Value secret.Password = field.Value
case "notesPlain":
secret.SecretText = field.Value
} }
} }
} }
if item.Details.Password != nil && *item.Details.Password != "" {
secret.Password = *item.Details.Password
}
if item.Details.Notes != "" {
secret.SecretText = item.Details.Notes
}
return secret, nil return secret, nil
} }

View File

@ -5,23 +5,13 @@ import (
) )
type field struct { type field struct {
Name string `json:"name"` Name string `json:"label"`
Value string `json:"value"` Value string `json:"value"`
} }
type details struct { type response struct {
UUID string `json:"id"`
Updated time.Time `json:"created_at"`
Fields []field `json:"fields"` Fields []field `json:"fields"`
Notes string `json:"notesPlain"`
Password *string `json:"password;omitempty"`
}
type overview struct {
Title string `json:"title"` Title string `json:"title"`
} }
type response struct {
UUID string `json:"uuid"`
Updated time.Time `json:"createdAt"`
Details details `json:"details"`
Overview overview `json:"overview"`
}

19
main.go
View File

@ -148,24 +148,11 @@ func buildOpClient() (*onepassword.Client, error) {
panic(err.Error()) panic(err.Error())
} }
domain, ok := os.LookupEnv("OP_DOMAIN") if _, ok := os.LookupEnv("OP_SERVICE_ACCOUNT_TOKEN"); !ok {
if !ok { return nil, fmt.Errorf("OP_SERVICE_ACCOUNT_TOKEN not specified")
return nil, fmt.Errorf("OP_DOMAIN not specified")
}
email, ok := os.LookupEnv("OP_EMAIL")
if !ok {
return nil, fmt.Errorf("OP_EMAIL not specified")
}
password, ok := os.LookupEnv("OP_PASSWORD")
if !ok {
return nil, fmt.Errorf("OP_PASSWORD not specified")
}
secretKey, ok := os.LookupEnv("OP_SECRET_KEY")
if !ok {
return nil, fmt.Errorf("OP_SECRET_KEY not specified")
} }
return onepassword.New(domain, email, password, secretKey) return onepassword.New()
} }
func parseAnnotations(annotations map[string]string) map[string]string { func parseAnnotations(annotations map[string]string) map[string]string {

View File

@ -16,26 +16,11 @@ spec:
- image: kube-1password-secrets - image: kube-1password-secrets
name: kube-1password-secrets name: kube-1password-secrets
env: env:
- name: OP_DOMAIN - name: OP_SERVICE_ACCOUNT_TOKEN
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: kube-1password-secrets name: kube-1password-secrets
key: OP_DOMAIN key: OP_SERVICE_ACCOUNT_TOKEN
- name: OP_EMAIL
valueFrom:
secretKeyRef:
name: kube-1password-secrets
key: OP_EMAIL
- name: OP_PASSWORD
valueFrom:
secretKeyRef:
name: kube-1password-secrets
key: OP_PASSWORD
- name: OP_SECRET_KEY
valueFrom:
secretKeyRef:
name: kube-1password-secrets
key: OP_SECRET_KEY
volumeMounts: volumeMounts:
- mountPath: "/root/.op" - mountPath: "/root/.op"
name: op name: op

View File

@ -1,4 +1 @@
OP_DOMAIN= OP_SERVICE_ACCOUNT_TOKEN=
OP_EMAIL=
OP_PASSWORD=
OP_SECRET_KEY=