add support for docker compose secrets
enables using [docker compose secrets](https://docs.docker.com/compose/use-secrets/) from arion, which includes: - [top-level `secrets` element](https://docs.docker.com/compose/compose-file/09-secrets/) defining the secrets to be used for the below two use-cases, exposing them at `/run/secrets/<secret_name>`. comes in flavors `file` vs `environment`. - run-time: [`services` top-level `secrets` element](https://docs.docker.com/compose/compose-file/05-services/#secrets) - build time: [build secrets](https://docs.docker.com/build/building/secrets/) (to be [mounted](https://docs.docker.com/build/building/secrets/#secret-mounts) in the `Dockerfile` like `RUN --mount=type=secret,id=<secret_name> ...`) unlike #52, i did not so far add support for their [long syntax](https://docs.docker.com/compose/compose-file/05-services/#long-syntax-4), which despite the confusing documentation appears [limited to Docker Swarm](https://github.com/docker/compose/issues/9648#issuecomment-1380290233), in my understanding limiting its use in Arion.
This commit is contained in:
parent
236f9dd82d
commit
a8b21575ff
10 changed files with 167 additions and 24 deletions
|
@ -19,6 +19,7 @@ data-files: nix/*.nix
|
|||
, nix/modules/composition/*.nix
|
||||
, nix/modules/networks/*.nix
|
||||
, nix/modules/nixos/*.nix
|
||||
, nix/modules/secrets/*.nix
|
||||
, nix/modules/service/*.nix
|
||||
, nix/modules/lib/*.nix
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"name": "unit-test-data"
|
||||
}
|
||||
},
|
||||
"secrets": {},
|
||||
"services": {
|
||||
"webserver": {
|
||||
"command": [
|
||||
|
|
|
@ -4,10 +4,18 @@
|
|||
"name": "unit-test-data"
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"foo": {
|
||||
"environment": "FOO"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"webserver": {
|
||||
"build": {
|
||||
"context": "<STOREPATH>"
|
||||
"context": "<STOREPATH>",
|
||||
"secrets": [
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
"environment": {},
|
||||
"ports": [
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
project.name = "unit-test-data";
|
||||
services.webserver.service = {
|
||||
build.context = "${./build-context}";
|
||||
build.secrets = ["foo"];
|
||||
ports = [
|
||||
"8080:80"
|
||||
];
|
||||
};
|
||||
secrets.foo.environment = "FOO";
|
||||
}
|
||||
|
|
|
@ -11,11 +11,15 @@ let
|
|||
networkRef = fragment:
|
||||
''See ${link "https://github.com/compose-spec/compose-spec/blob/${composeSpecRev}/06-networks.md#${fragment}" "Compose Spec Networks #${fragment}"}'';
|
||||
|
||||
secretRef = fragment:
|
||||
''See ${link "https://github.com/compose-spec/compose-spec/blob/${composeSpecRev}/09-secrets.md#${fragment}" "Compose Spec Secrets #${fragment}"}'';
|
||||
|
||||
in
|
||||
{
|
||||
inherit
|
||||
link
|
||||
networkRef
|
||||
serviceRef
|
||||
secretRef
|
||||
;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
./modules/composition/host-environment.nix
|
||||
./modules/composition/images.nix
|
||||
./modules/composition/networks.nix
|
||||
./modules/composition/secrets.nix
|
||||
./modules/composition/service-info.nix
|
||||
./modules/composition/composition.nix
|
||||
]
|
||||
]
|
||||
|
|
|
@ -68,6 +68,14 @@ in
|
|||
description = "A attribute set of volume configurations.";
|
||||
default = {};
|
||||
};
|
||||
docker-compose.secrets = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.unspecified;
|
||||
description = ''
|
||||
An attribute set of secret configurations. For more info, see:
|
||||
https://docs.docker.com/compose/compose-file/09-secrets/
|
||||
'';
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
out.dockerComposeYaml = pkgs.writeText "docker-compose.yaml" config.out.dockerComposeYamlText;
|
||||
|
@ -79,6 +87,7 @@ in
|
|||
services = lib.mapAttrs (k: c: c.out.service) config.services;
|
||||
x-arion = config.docker-compose.extended;
|
||||
volumes = config.docker-compose.volumes;
|
||||
secrets = config.docker-compose.secrets;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
33
src/nix/modules/composition/secrets.nix
Normal file
33
src/nix/modules/composition/secrets.nix
Normal file
|
@ -0,0 +1,33 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
inherit (import ../../lib.nix { inherit lib; })
|
||||
link
|
||||
;
|
||||
in
|
||||
{
|
||||
|
||||
options = {
|
||||
secrets = mkOption {
|
||||
type = types.lazyAttrsOf (types.submoduleWith {
|
||||
modules = [
|
||||
../secrets/secret.nix
|
||||
];
|
||||
});
|
||||
description = ''
|
||||
See ${link "https://docs.docker.com/compose/compose-file/09-secrets/" "Docker Compose Secrets"}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
secrets = {};
|
||||
docker-compose.secrets = lib.mapAttrs (k: v: v.out) config.secrets;
|
||||
|
||||
};
|
||||
}
|
55
src/nix/modules/secrets/secret.nix
Normal file
55
src/nix/modules/secrets/secret.nix
Normal file
|
@ -0,0 +1,55 @@
|
|||
{ config, lib, options, ... }:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
optionalAttrs
|
||||
types
|
||||
;
|
||||
inherit (import ../../lib.nix { inherit lib; })
|
||||
secretRef
|
||||
;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
file = mkOption {
|
||||
description = ''
|
||||
The secret is created with the contents of the file at the specified path.
|
||||
${secretRef "file"}
|
||||
'';
|
||||
type = types.nullOr types.str;
|
||||
};
|
||||
|
||||
environment = mkOption {
|
||||
description = ''
|
||||
The secret is created with the value of an environment variable.
|
||||
${secretRef "environment"}
|
||||
'';
|
||||
type = types.nullOr types.str;
|
||||
};
|
||||
|
||||
out = mkOption {
|
||||
internal = true;
|
||||
description = ''
|
||||
Defines sensitive data that is granted to the services in your Compose application.
|
||||
The source of the secret is either `file` or `environment`.
|
||||
'';
|
||||
type = lib.types.attrsOf lib.types.raw or lib.types.unspecified;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
out =
|
||||
lib.mapAttrs
|
||||
(k: opt: opt.value)
|
||||
(lib.filterAttrs
|
||||
(k: opt: opt.isDefined)
|
||||
{
|
||||
inherit (options)
|
||||
file
|
||||
environment
|
||||
;
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
|
@ -57,29 +57,56 @@ in
|
|||
default = [];
|
||||
description = serviceRef "tmpfs";
|
||||
};
|
||||
service.build.context = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
Locates a Dockerfile to use for creating an image to use in this service.
|
||||
service.build = mkOption {
|
||||
default = {};
|
||||
description = serviceRef "build";
|
||||
type = submodule ({ options, ...}: {
|
||||
options = {
|
||||
_out = mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
default = lib.mapAttrs (k: opt: opt.value) (lib.filterAttrs (_: opt: opt.value != null) { inherit (options) context dockerfile target secrets; });
|
||||
};
|
||||
context = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
Locates a Dockerfile to use for creating an image to use in this service.
|
||||
|
||||
https://docs.docker.com/compose/compose-file/build/#context
|
||||
'';
|
||||
https://docs.docker.com/compose/compose-file/build/#context
|
||||
'';
|
||||
};
|
||||
dockerfile = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
Sets an alternate Dockerfile. A relative path is resolved from the build context.
|
||||
https://docs.docker.com/compose/compose-file/build/#dockerfile
|
||||
'';
|
||||
};
|
||||
target = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
Defines the stage to build as defined inside a multi-stage Dockerfile.
|
||||
https://docs.docker.com/compose/compose-file/build/#target
|
||||
'';
|
||||
};
|
||||
secrets = mkOption {
|
||||
type = nullOr (listOf str);
|
||||
default = null;
|
||||
description = ''
|
||||
Build-time secrets exposed to the service.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
service.build.dockerfile = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
service.secrets = mkOption {
|
||||
type = listOf str;
|
||||
default = [];
|
||||
description = ''
|
||||
Sets an alternate Dockerfile. A relative path is resolved from the build context.
|
||||
https://docs.docker.com/compose/compose-file/build/#dockerfile
|
||||
'';
|
||||
};
|
||||
service.build.target = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
Defines the stage to build as defined inside a multi-stage Dockerfile.
|
||||
https://docs.docker.com/compose/compose-file/build/#target
|
||||
Run-time secrets exposed to the service.
|
||||
'';
|
||||
};
|
||||
service.hostname = mkOption {
|
||||
|
@ -353,8 +380,8 @@ in
|
|||
;
|
||||
} // lib.optionalAttrs (config.service.image != null) {
|
||||
inherit (config.service) image;
|
||||
} // lib.optionalAttrs (config.service.build.context != null ) {
|
||||
build = lib.filterAttrs (n: v: v != null) config.service.build;
|
||||
} // lib.optionalAttrs (config.service.build._out != {}) {
|
||||
build = config.service.build._out;
|
||||
} // lib.optionalAttrs (cap_add != []) {
|
||||
inherit cap_add;
|
||||
} // lib.optionalAttrs (cap_drop != []) {
|
||||
|
@ -379,6 +406,8 @@ in
|
|||
inherit (config.service) external_links;
|
||||
} // lib.optionalAttrs (config.service.extra_hosts != []) {
|
||||
inherit (config.service) extra_hosts;
|
||||
} // lib.optionalAttrs (config.service.secrets != []) {
|
||||
inherit (config.service) secrets;
|
||||
} // lib.optionalAttrs (config.service.hostname != null) {
|
||||
inherit (config.service) hostname;
|
||||
} // lib.optionalAttrs (config.service.dns != []) {
|
||||
|
|
Loading…
Reference in a new issue