diff --git a/cmd/dagger/cmd/root.go b/cmd/dagger/cmd/root.go index 4d0f4cb1..37252ab6 100644 --- a/cmd/dagger/cmd/root.go +++ b/cmd/dagger/cmd/root.go @@ -9,7 +9,6 @@ import ( "github.com/spf13/viper" "go.dagger.io/dagger/cmd/dagger/cmd/mod" "go.dagger.io/dagger/cmd/dagger/logger" - "go.dagger.io/dagger/keychain" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -34,15 +33,7 @@ func init() { rootCmd.PersistentFlags().String("project", "", "Specify a project directory (defaults to current)") rootCmd.PersistentPreRun = func(cmd *cobra.Command, _ []string) { - lg := logger.New() - ctx := lg.WithContext(cmd.Context()) - go checkVersion() - - err := keychain.EnsureDefaultKey(ctx) - if err != nil { - lg.Fatal().Err(err).Msg("failed to generate default key") - } } rootCmd.PersistentPostRun = func(*cobra.Command, []string) { warnVersion() diff --git a/keychain/encrypt.go b/keychain/encrypt.go deleted file mode 100644 index 77a7a225..00000000 --- a/keychain/encrypt.go +++ /dev/null @@ -1,162 +0,0 @@ -package keychain - -import ( - "context" - "fmt" - "os" - "time" - - "go.mozilla.org/sops/v3" - sopsaes "go.mozilla.org/sops/v3/aes" - sopsage "go.mozilla.org/sops/v3/age" - "go.mozilla.org/sops/v3/cmd/sops/common" - sopskeys "go.mozilla.org/sops/v3/keys" - sopsyaml "go.mozilla.org/sops/v3/stores/yaml" - "go.mozilla.org/sops/v3/version" -) - -var ( - cipher = sopsaes.NewCipher() -) - -// setupEnv: hack to inject a SOPS env var for age -func setupEnv() error { - p, err := Path() - if err != nil { - return err - } - return os.Setenv("SOPS_AGE_KEY_FILE", p) -} - -// Encrypt data using SOPS with the AGE backend, using the provided public key -func Encrypt(ctx context.Context, path string, plaintext []byte, key string) ([]byte, error) { - if err := setupEnv(); err != nil { - return nil, err - } - - store := &sopsyaml.Store{} - branches, err := store.LoadPlainFile(plaintext) - if err != nil { - return nil, err - } - - ageKeys, err := sopsage.MasterKeysFromRecipients(key) - if err != nil { - return nil, err - } - ageMasterKeys := make([]sopskeys.MasterKey, 0, len(ageKeys)) - for _, k := range ageKeys { - ageMasterKeys = append(ageMasterKeys, k) - } - var group sops.KeyGroup - group = append(group, ageMasterKeys...) - - tree := sops.Tree{ - Branches: branches, - Metadata: sops.Metadata{ - KeyGroups: []sops.KeyGroup{group}, - EncryptedSuffix: "secret", - Version: version.Version, - }, - FilePath: path, - } - - // Generate a data key - dataKey, errs := tree.GenerateDataKey() - if len(errs) > 0 { - return nil, fmt.Errorf("error encrypting the data key with one or more master keys: %v", errs) - } - - err = common.EncryptTree(common.EncryptTreeOpts{ - DataKey: dataKey, Tree: &tree, Cipher: cipher, - }) - if err != nil { - return nil, err - } - return store.EmitEncryptedFile(tree) -} - -// Reencrypt a file with new content using the same keys -func Reencrypt(_ context.Context, path string, plaintext []byte) ([]byte, error) { - if err := setupEnv(); err != nil { - return nil, err - } - - current, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - // Load the encrypted file - store := &sopsyaml.Store{} - tree, err := store.LoadEncryptedFile(current) - if err != nil { - return nil, err - } - - // Update the file with the new data - newBranches, err := store.LoadPlainFile(plaintext) - if err != nil { - return nil, err - } - tree.Branches = newBranches - - // Re-encrypt the file - key, err := tree.Metadata.GetDataKey() - if err != nil { - return nil, err - } - err = common.EncryptTree(common.EncryptTreeOpts{ - DataKey: key, Tree: &tree, Cipher: cipher, - }) - if err != nil { - return nil, err - } - - return store.EmitEncryptedFile(tree) -} - -// Decrypt data using sops -func Decrypt(_ context.Context, encrypted []byte) ([]byte, error) { - if err := setupEnv(); err != nil { - return nil, err - } - - store := &sopsyaml.Store{} - - // Load SOPS file and access the data key - tree, err := store.LoadEncryptedFile(encrypted) - if err != nil { - return nil, err - } - key, err := tree.Metadata.GetDataKey() - if err != nil { - if userErr, ok := err.(sops.UserError); ok { - err = fmt.Errorf(userErr.UserError()) - } - return nil, err - } - - // Decrypt the tree - mac, err := tree.Decrypt(key, cipher) - if err != nil { - return nil, err - } - - // Compute the hash of the cleartext tree and compare it with - // the one that was stored in the document. If they match, - // integrity was preserved - originalMac, err := cipher.Decrypt( - tree.Metadata.MessageAuthenticationCode, - key, - tree.Metadata.LastModified.Format(time.RFC3339), - ) - if err != nil { - return nil, err - } - if originalMac != mac { - return nil, fmt.Errorf("failed to verify data integrity. expected mac %q, got %q", originalMac, mac) - } - - return store.EmitPlainFile(tree.Branches) -} diff --git a/keychain/keys.go b/keychain/keys.go deleted file mode 100644 index 017a563b..00000000 --- a/keychain/keys.go +++ /dev/null @@ -1,140 +0,0 @@ -package keychain - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "time" - - "filippo.io/age" - "github.com/mitchellh/go-homedir" - "github.com/rs/zerolog/log" -) - -func Path() (string, error) { - return homedir.Expand("~/.config/dagger/keys.txt") -} - -func EnsureDefaultKey(ctx context.Context) error { - keysFile, err := Path() - if err != nil { - return err - } - - // If the keys file already exists, there's nothing to do. - _, err = os.Stat(keysFile) - if err == nil { - return nil - } - - // If we got a different error than not existent, abort - if !errors.Is(err, os.ErrNotExist) { - return err - } - - // Attempt a migration from the old keys file - migrated, err := migrateKeys(ctx, keysFile) - if err != nil { - return err - } - - // If we migrated a previous identity, stop here. - if migrated { - return nil - } - - // Otherwise, generate a new key - log.Ctx(ctx).Debug().Msg("generating default key pair") - _, err = Generate(ctx) - return err -} - -// migrateKeys attempts a migration from `~/.dagger/keys.txt` to `~/.config/dagger/keys.txt` -func migrateKeys(ctx context.Context, keysFile string) (bool, error) { - oldKeysFile, err := homedir.Expand("~/.dagger/keys.txt") - if err != nil { - return false, err - } - - if _, err := os.Stat(oldKeysFile); err != nil { - return false, nil - } - - if err := os.MkdirAll(filepath.Dir(keysFile), 0700); err != nil { - return false, err - } - - log.Ctx(ctx).Info().Msg("migrating keychain") - return true, os.Rename(oldKeysFile, keysFile) -} - -func Default(ctx context.Context) (string, error) { - keys, err := List(ctx) - if err != nil { - return "", err - } - if len(keys) == 0 { - return "", errors.New("no identities found in the keys file") - } - - return keys[0].Recipient().String(), nil -} - -func Generate(ctx context.Context) (string, error) { - keysFile, err := Path() - if err != nil { - return "", err - } - - k, err := age.GenerateX25519Identity() - if err != nil { - return "", fmt.Errorf("internal error: %v", err) - } - - if err := os.MkdirAll(filepath.Dir(keysFile), 0700); err != nil { - return "", err - } - f, err := os.OpenFile(keysFile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) - if err != nil { - return "", fmt.Errorf("failed to open keys file %q: %v", keysFile, err) - } - defer f.Close() - fmt.Fprintf(f, "# created: %s\n", time.Now().Format(time.RFC3339)) - fmt.Fprintf(f, "# public key: %s\n", k.Recipient()) - fmt.Fprintf(f, "%s\n", k) - - pubkey := k.Recipient().String() - - log.Ctx(ctx).Debug().Str("publicKey", pubkey).Msg("keypair generated") - - return pubkey, nil -} - -func List(ctx context.Context) ([]*age.X25519Identity, error) { - keysFile, err := Path() - if err != nil { - return nil, err - } - - f, err := os.Open(keysFile) - if err != nil { - return nil, fmt.Errorf("failed to open keys file %q: %w", keysFile, err) - } - ids, err := age.ParseIdentities(f) - if err != nil { - return nil, fmt.Errorf("failed to parse input: %w", err) - } - - keys := make([]*age.X25519Identity, 0, len(ids)) - for _, id := range ids { - key, ok := id.(*age.X25519Identity) - if !ok { - return nil, fmt.Errorf("internal error: unexpected identity type: %T", id) - } - keys = append(keys, key) - } - - return keys, nil -}