Open dot-mike opened 2 years ago
Have the same problem, latest version of sops (v3.7.3) and age (v1.0.0).
This probably requires to include age v1.1.0, as only there was included the plugin mechanism required for the age-plugin-yubikey. Having age v1.1.0-rc in the path does not seem to be of any help, as it is included as a library, so library dependency must be updated once age v1.1.0 is released.
I have the same problem using latest versions of sops and age.
I have the same problem even when doing a sops make install
from the latest master branch having bumped the age package dependency to v1.1.0-rc.1.
Age got a v1.1.1 release a few days ago. Now it isn't a release candidate anymore.
A bump to the latest age release makes 100% sense but I did a make build with the newest version specified as the age dependency but still experienced this issue. Seems that something in the sops code needs to change to enable on-yubikey encryption keys still.
check your age version. Maybe the brew wasnt updated already. You need version 1.1.x
check your age version. Maybe the brew wasnt updated already. You need version 1.1.x
Yes, running brew update
, brew upgrade
did the trick, by upgrading age from 1.0.x to 1.1.x
Just dropping in to confirm that this issue still exists with age 1.1.1
and sops build from the develop
branch as well as 3.7.3
.
Still getting the same issue when trying to encrypt with a yubikey-based age identity.
In my environment age --version
shows v1.1.1
and I am able to encrypt/decrypt directly with age without issue with both yubikey-based and non-yubikey-based age identities. I am using the brew installed version.
Regardless of whether I use the brew installed version of sops (v3.7.3) or I build it from source (first updating the vendored age go module dependency to v1.1.1), I get the original OP's error on encryption operations. And, if I use a non-yubikey-based age identity everything works fine.
The yubikey-based age public key (aka receipient) is of the form: 'age1yubikey
✗ sops --version
sops 3.7.3 (latest)
✗ age --version
v1.1.1
✗ sops --encrypt --age $(age-plugin-yubikey -l --serial 11087061 --slot 1 | grep -vE '^#') controlplane.yaml
failed to parse input as Bech32-encoded age public key: malformed recipient "age1yubikey1qgsrfvr...snip...": invalid type "age1yubikey"
However it should be noted this is with age
, not sops
➜ cat main.go
package main
import (
"filippo.io/age"
"fmt"
)
func main() {
foo, err := age.ParseX25519Recipient("age1yubikey1qgsr...snip")
if err != nil {
fmt.Println("failed to parse input as Bech32-encoded age public key: %w", err)
} else {
fmt.Println(fmt.Sprintf("%+v", foo))
}
}
➜ go run main.go
failed to parse input as Bech32-encoded age public key: %w malformed recipient
"age1yubikey1qgsr...snip": invalid type "age1yubikey"
from here
Ive started a discussion upstream here if anyone has anything to add or wants to follow
Quick summary here.
Age Plugin api is marked as internal right now. No exposed api exists yet for supporting plugins directly.
age
command currently handles dispatching age1/age1pluginName1 (yes, 1 is the deliminator) itself in the command library age/cmd/age/parse.go
. This file can probably be used as a hacky way to add support, but it comes with a terminalUI which sops may want to but cannot replace.
I outright stole the code from parse.go and moved the plugin out of internal to test it locally to confirm it works with just code from these 2 files. If its not clear, I am not recommending this experiment. Just noting it does work and as hacky as it is, itsn't terribly hard to enable once you know where everything is. So it will likely be trivial once the api is finalized and exposed. Hardest part is probably deciding how to handle pin input and prompts. terminal? pinentry? Is SOPS_AGE_PIN env variable a terrible idea to support?
Age Plugin api is marked as internal right now. No exposed api exists yet for supporting plugins directly.
Not sure if I find time to try this myself anytime soon, but as sops pgp backend supports both, using go-crypto/opengpg
a library and shelling out to gpg
, a similar solution might be possible for age? i.e. if we had an option to just call age
or rage
, support for plugins would be free, if I am not mistaken?
Getting inspiration from https://github.com/FiloSottile/age/issues/86#issuecomment-752639799, this is how you can approximate using yubikey-stored age key with sops today:
The idea is to create an age key, but store it encrypted, where the encryption key is the yubikey-stored age key. Then when invoking sops, decrypt the stored key on the fly using the yubikey. I think this is less secure than using the yubikey-age-key directly, but better than nothing (as long as you don't store the decrypted key anywhere just pass to sops).
Edit: Elaboration on why this is not entirely like a yubikey-stored key: if the host is compromised, an attacker can intercept the (temporarily) decrypted age key and steal it, performing further decrypts (or even encrypts) with it in the future. If the decompression of the sops-protected secret were done using a fully yubikey-stored age key, then the attacker can only steal the decompressed secret values, but not the key itself. So "only" the current set of secrets is compromised, but not the key itself.
Demonstration:
$ age-keygen | age -e -r age1yubikey1q0p7guhr6dg2d56y66yxkzmwy98wxxcfuak7dt36ndqz95ld4tvr6fuah4n -o key.enc
Public key: age1uyvqk9kqjenmnwn08szr87cp6vgrr6dltt8cgardhhd5x0qfjcxqtdjucz
$ sops -e --age age1uyvqk9kqjenmnwn08szr87cp6vgrr6dltt8cgardhhd5x0qfjcxqtdjucz -i y.yaml
$ SOPS_AGE_KEY=$(age -i /path/to/the/age-yubikey-identity-0f5da44b.txt -d key.enc) sops -d y.yaml
# Enter PIN
# touch
Hello! I'm using Age with Yubikey. Support for plugins was recently added to Age v1.1.0-rc.1 repository, but the validation still fails in SOPS. Looks like the validation for identity fails because the parse-method of Age was never updated outside of Cmd... Please look into adding support using Age with Yubikey, the plugin I'm using is this: https://github.com/str4d/age-plugin-yubikey
The commits inAge repo that adds plugin functionality : https://github.com/FiloSottile/age/compare/cff70cffe2f665ef67cf243daafb064f0feb61a9...87a982b72e813859bb7eb6d1e0e9dcb7ceec63df
Example error: