mirror of
https://github.com/Mic92/sops-nix.git
synced 2025-12-26 14:14:58 +08:00
Allow to set uid and gid instead of owner and group. No checks will be performed when uid and gid are set.
```
sops.secrets = {
sslCertificate = {
sopsFile = ./secrets.yaml;
owner = "";
group = "";
uid = config.containers."nginx".config.users.users."nginx".uid;
gid = config.containers."nginx".config.users.groups."nginx".gid;
};
sslCertificateKey = {
sopsFile = ./secrets.yaml;
owner = "";
group = "";
uid = config.containers."nginx".config.users.users."nginx".uid;
gid = config.containers."nginx".config.users.groups."nginx".gid;
};
};
```
Co-authored-by: Jörg Thalheim <Mic92@users.noreply.github.com>
This commit is contained in:
parent
26642e8f19
commit
a4c33bfecb
5 changed files with 132 additions and 44 deletions
|
|
@ -29,8 +29,10 @@ type secret struct {
|
|||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Path string `json:"path"`
|
||||
Owner string `json:"owner"`
|
||||
Group string `json:"group"`
|
||||
Owner *string `json:"owner,omitempty"`
|
||||
UID int `json:"uid"`
|
||||
Group *string `json:"group,omitempty"`
|
||||
GID int `json:"gid"`
|
||||
SopsFile string `json:"sopsFile"`
|
||||
Format FormatType `json:"format"`
|
||||
Mode string `json:"mode"`
|
||||
|
|
@ -475,25 +477,34 @@ func (app *appContext) validateSecret(secret *secret) error {
|
|||
secret.group = 0
|
||||
} else if app.checkMode == Off || app.ignorePasswd {
|
||||
// we only access to the user/group during deployment
|
||||
owner, err := user.Lookup(secret.Owner)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup user '%s': %w", secret.Owner, err)
|
||||
}
|
||||
ownerNr, err := strconv.ParseUint(owner.Uid, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse uid %s: %w", owner.Uid, err)
|
||||
}
|
||||
secret.owner = int(ownerNr)
|
||||
|
||||
group, err := user.LookupGroup(secret.Group)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup group '%s': %w", secret.Group, err)
|
||||
if secret.Owner == nil {
|
||||
secret.owner = secret.UID
|
||||
} else {
|
||||
owner, err := user.Lookup(*secret.Owner)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup user '%s': %w", *secret.Owner, err)
|
||||
}
|
||||
uid, err := strconv.ParseUint(owner.Uid, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse uid %s: %w", owner.Uid, err)
|
||||
}
|
||||
secret.owner = int(uid)
|
||||
}
|
||||
groupNr, err := strconv.ParseUint(group.Gid, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse gid %s: %w", group.Gid, err)
|
||||
|
||||
if secret.Group == nil {
|
||||
secret.group = secret.GID
|
||||
} else {
|
||||
group, err := user.LookupGroup(*secret.Group)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup group '%s': %w", *secret.Group, err)
|
||||
}
|
||||
gid, err := strconv.ParseUint(group.Gid, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot parse gid %s: %w", group.Gid, err)
|
||||
}
|
||||
secret.group = int(gid)
|
||||
}
|
||||
secret.group = int(groupNr)
|
||||
}
|
||||
|
||||
if secret.Format == "" {
|
||||
|
|
|
|||
|
|
@ -98,12 +98,14 @@ func testGPG(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
nobody := "nobody"
|
||||
nogroup := "nogroup"
|
||||
// should create a symlink
|
||||
yamlSecret := secret{
|
||||
Name: "test",
|
||||
Key: "test_key",
|
||||
Owner: "nobody",
|
||||
Group: "nogroup",
|
||||
Owner: &nobody,
|
||||
Group: &nogroup,
|
||||
SopsFile: path.Join(assets, "secrets.yaml"),
|
||||
Path: path.Join(testdir.path, "test-target"),
|
||||
Mode: "0400",
|
||||
|
|
@ -112,12 +114,13 @@ func testGPG(t *testing.T) {
|
|||
}
|
||||
|
||||
var jsonSecret, binarySecret, dotenvSecret, iniSecret secret
|
||||
root := "root"
|
||||
// should not create a symlink
|
||||
jsonSecret = yamlSecret
|
||||
jsonSecret.Name = "test2"
|
||||
jsonSecret.Owner = "root"
|
||||
jsonSecret.Owner = &root
|
||||
jsonSecret.Format = "json"
|
||||
jsonSecret.Group = "root"
|
||||
jsonSecret.Group = &root
|
||||
jsonSecret.SopsFile = path.Join(assets, "secrets.json")
|
||||
jsonSecret.Path = path.Join(testdir.secretsPath, "test2")
|
||||
jsonSecret.Mode = "0700"
|
||||
|
|
@ -130,16 +133,16 @@ func testGPG(t *testing.T) {
|
|||
|
||||
dotenvSecret = yamlSecret
|
||||
dotenvSecret.Name = "test4"
|
||||
dotenvSecret.Owner = "root"
|
||||
dotenvSecret.Group = "root"
|
||||
dotenvSecret.Owner = &root
|
||||
dotenvSecret.Group = &root
|
||||
dotenvSecret.Format = "dotenv"
|
||||
dotenvSecret.SopsFile = path.Join(assets, "secrets.env")
|
||||
dotenvSecret.Path = path.Join(testdir.secretsPath, "test4")
|
||||
|
||||
iniSecret = yamlSecret
|
||||
iniSecret.Name = "test5"
|
||||
iniSecret.Owner = "root"
|
||||
iniSecret.Group = "root"
|
||||
iniSecret.Owner = &root
|
||||
iniSecret.Group = &root
|
||||
iniSecret.Format = "ini"
|
||||
iniSecret.SopsFile = path.Join(assets, "secrets.ini")
|
||||
iniSecret.Path = path.Join(testdir.secretsPath, "test5")
|
||||
|
|
@ -214,11 +217,13 @@ func testSSHKey(t *testing.T) {
|
|||
ok(t, err)
|
||||
file.Close()
|
||||
|
||||
nobody := "nobody"
|
||||
nogroup := "nogroup"
|
||||
s := secret{
|
||||
Name: "test",
|
||||
Key: "test_key",
|
||||
Owner: "nobody",
|
||||
Group: "nogroup",
|
||||
Owner: &nobody,
|
||||
Group: &nogroup,
|
||||
SopsFile: path.Join(assets, "secrets.yaml"),
|
||||
Path: target,
|
||||
Mode: "0400",
|
||||
|
|
@ -247,11 +252,13 @@ func TestAge(t *testing.T) {
|
|||
ok(t, err)
|
||||
file.Close()
|
||||
|
||||
nobody := "nobody"
|
||||
nogroup := "nogroup"
|
||||
s := secret{
|
||||
Name: "test",
|
||||
Key: "test_key",
|
||||
Owner: "nobody",
|
||||
Group: "nogroup",
|
||||
Owner: &nobody,
|
||||
Group: &nogroup,
|
||||
SopsFile: path.Join(assets, "secrets.yaml"),
|
||||
Path: target,
|
||||
Mode: "0400",
|
||||
|
|
@ -280,11 +287,13 @@ func TestAgeWithSSH(t *testing.T) {
|
|||
ok(t, err)
|
||||
file.Close()
|
||||
|
||||
nobody := "nobody"
|
||||
nogroup := "nogroup"
|
||||
s := secret{
|
||||
Name: "test",
|
||||
Key: "test_key",
|
||||
Owner: "nobody",
|
||||
Group: "nogroup",
|
||||
Owner: &nobody,
|
||||
Group: &nogroup,
|
||||
SopsFile: path.Join(assets, "secrets.yaml"),
|
||||
Path: target,
|
||||
Mode: "0400",
|
||||
|
|
@ -314,11 +323,13 @@ func TestValidateManifest(t *testing.T) {
|
|||
testdir := newTestDir(t)
|
||||
defer testdir.Remove()
|
||||
|
||||
nobody := "nobody"
|
||||
nogroup := "nogroup"
|
||||
s := secret{
|
||||
Name: "test",
|
||||
Key: "test_key",
|
||||
Owner: "nobody",
|
||||
Group: "nogroup",
|
||||
Owner: &nobody,
|
||||
Group: &nogroup,
|
||||
SopsFile: path.Join(assets, "secrets.yaml"),
|
||||
Path: path.Join(testdir.path, "test-target"),
|
||||
Mode: "0400",
|
||||
|
|
|
|||
|
|
@ -112,12 +112,41 @@ in {
|
|||
|
||||
age-keys = testers.runNixOSTest {
|
||||
name = "sops-age-keys";
|
||||
nodes.machine = { lib, ... }: {
|
||||
nodes.machine = { config, ... }: {
|
||||
imports = [ ../../modules/sops ];
|
||||
sops = {
|
||||
age.keyFile = "/run/age-keys.txt";
|
||||
defaultSopsFile = ./test-assets/secrets.yaml;
|
||||
secrets.test_key = { };
|
||||
secrets = {
|
||||
test_key = { };
|
||||
|
||||
test_key_someuser_somegroup = {
|
||||
uid = config.users.users."someuser".uid;
|
||||
gid = config.users.groups."somegroup".gid;
|
||||
key = "test_key";
|
||||
};
|
||||
test_key_someuser_root = {
|
||||
uid = config.users.users."someuser".uid;
|
||||
key = "test_key";
|
||||
};
|
||||
test_key_root_root = {
|
||||
key = "test_key";
|
||||
};
|
||||
test_key_1001_1001 = {
|
||||
uid = 1001;
|
||||
gid = 1001;
|
||||
key = "test_key";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users.users."someuser" = {
|
||||
uid = 1000;
|
||||
group = "somegroup";
|
||||
isNormalUser = true;
|
||||
};
|
||||
users.groups."somegroup" = {
|
||||
gid = 1000;
|
||||
};
|
||||
|
||||
# must run before sops sets up keys
|
||||
|
|
@ -130,6 +159,22 @@ in {
|
|||
testScript = ''
|
||||
start_all()
|
||||
machine.succeed("cat /run/secrets/test_key | grep -q test_value")
|
||||
|
||||
with subtest("test ownership"):
|
||||
machine.succeed("[ $(stat -c%u /run/secrets/test_key_someuser_somegroup) = '1000' ]")
|
||||
machine.succeed("[ $(stat -c%g /run/secrets/test_key_someuser_somegroup) = '1000' ]")
|
||||
machine.succeed("[ $(stat -c%U /run/secrets/test_key_someuser_somegroup) = 'someuser' ]")
|
||||
machine.succeed("[ $(stat -c%G /run/secrets/test_key_someuser_somegroup) = 'somegroup' ]")
|
||||
|
||||
machine.succeed("[ $(stat -c%u /run/secrets/test_key_someuser_root) = '1000' ]")
|
||||
machine.succeed("[ $(stat -c%g /run/secrets/test_key_someuser_root) = '0' ]")
|
||||
machine.succeed("[ $(stat -c%U /run/secrets/test_key_someuser_root) = 'someuser' ]")
|
||||
machine.succeed("[ $(stat -c%G /run/secrets/test_key_someuser_root) = 'root' ]")
|
||||
|
||||
machine.succeed("[ $(stat -c%u /run/secrets/test_key_1001_1001) = '1001' ]")
|
||||
machine.succeed("[ $(stat -c%g /run/secrets/test_key_1001_1001) = '1001' ]")
|
||||
machine.succeed("[ $(stat -c%U /run/secrets/test_key_1001_1001) = 'UNKNOWN' ]")
|
||||
machine.succeed("[ $(stat -c%G /run/secrets/test_key_1001_1001) = 'UNKNOWN' ]")
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -142,6 +187,7 @@ in {
|
|||
type = "ed25519";
|
||||
path = ./test-assets/ssh-ed25519-key;
|
||||
}];
|
||||
|
||||
sops = {
|
||||
defaultSopsFile = ./test-assets/secrets.yaml;
|
||||
secrets.test_key = { };
|
||||
|
|
@ -161,7 +207,7 @@ in {
|
|||
|
||||
pgp-keys = testers.runNixOSTest {
|
||||
name = "sops-pgp-keys";
|
||||
nodes.server = { pkgs, lib, config, ... }: {
|
||||
nodes.server = { lib, config, ... }: {
|
||||
imports = [ ../../modules/sops ];
|
||||
|
||||
users.users.someuser = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue