oci.nix (6059B)
1 { 2 lib, 3 pkgs, 4 }: 5 { 6 serviceName, 7 package, 8 binaryName, 9 buildInfo, 10 }: 11 assert lib.assertMsg pkgs.stdenv.isLinux "service OCI images require a Linux builder"; 12 assert lib.assertMsg ( 13 pkgs.stdenv.hostPlatform.isx86_64 14 ) "service OCI images support only x86_64-linux"; 15 assert lib.assertMsg ( 16 builtins.isString serviceName 17 && builtins.stringLength serviceName <= 128 18 && builtins.match "^[a-z][a-z0-9_]*$" serviceName != null 19 ) "serviceName must be a lowercase snake-case identifier"; 20 assert lib.assertMsg (lib.isDerivation package) "package must be a derivation"; 21 assert lib.assertMsg ( 22 (package.passthru.radrootsServicePackage.schema or null) == "radroots.service-package.v1" 23 && (package.passthru.radrootsServicePackage.servicePackage or null) == binaryName 24 && (package.passthru.radrootsServicePackage.binaryName or null) == binaryName 25 && (package.passthru.radrootsServicePackage.serviceLicense or null) == "AGPL-3.0-or-later" 26 ) "package must carry the governed Cargo-derived service identity and license"; 27 assert lib.assertMsg ( 28 builtins.isString binaryName 29 && builtins.stringLength binaryName <= 128 30 && builtins.match "^[a-z][a-z0-9_-]*$" binaryName != null 31 ) "binaryName must be a lowercase Cargo binary identifier"; 32 assert lib.assertMsg (builtins.isAttrs buildInfo) "buildInfo must be an attribute set"; 33 assert lib.assertMsg ( 34 builtins.attrNames buildInfo == [ 35 "contractVersions" 36 "featureProfile" 37 "libRevision" 38 "rustVersion" 39 "serviceCommit" 40 "serviceVersion" 41 "target" 42 ] 43 ) "buildInfo must contain exactly the governed service build fields"; 44 assert lib.assertMsg ( 45 builtins.isString buildInfo.serviceVersion 46 && builtins.stringLength buildInfo.serviceVersion <= 128 47 && builtins.match "^[A-Za-z0-9][A-Za-z0-9_.-]*$" buildInfo.serviceVersion != null 48 ) "buildInfo.serviceVersion must be a bounded image-tag-safe value"; 49 assert lib.assertMsg ( 50 builtins.isString buildInfo.serviceCommit 51 && builtins.match "^[0-9a-f]{40}$" buildInfo.serviceCommit != null 52 ) "buildInfo.serviceCommit must be a full lowercase Git revision"; 53 assert lib.assertMsg ( 54 builtins.isString buildInfo.libRevision 55 && builtins.match "^[0-9a-f]{40}$" buildInfo.libRevision != null 56 ) "buildInfo.libRevision must be a full lowercase Git revision"; 57 assert lib.assertMsg ( 58 buildInfo.rustVersion == "1.97.1" 59 ) "buildInfo.rustVersion must match the governed Rust toolchain"; 60 assert lib.assertMsg ( 61 buildInfo.target == pkgs.stdenv.hostPlatform.rust.rustcTarget 62 ) "buildInfo.target must match the package host platform"; 63 assert lib.assertMsg ( 64 buildInfo.featureProfile == "service-host" 65 ) "buildInfo.featureProfile must select the service-host profile"; 66 assert lib.assertMsg (builtins.isAttrs buildInfo.contractVersions) ( 67 "buildInfo.contractVersions must be an attribute set" 68 ); 69 assert lib.assertMsg ( 70 builtins.attrNames buildInfo.contractVersions == [ 71 "admin" 72 "config" 73 "provider" 74 "state" 75 "status" 76 ] 77 ) "buildInfo.contractVersions must contain exactly the governed contract versions"; 78 assert lib.assertMsg (lib.all 79 (version: builtins.isInt version && version > 0 && version <= 4294967295) 80 (builtins.attrValues buildInfo.contractVersions) 81 ) "every buildInfo contract version must be a positive u32"; 82 let 83 imageName = lib.replaceStrings [ "_" ] [ "-" ] serviceName; 84 user = "65532:65532"; 85 mountPaths = [ 86 "/etc/radroots/services/${serviceName}" 87 "/etc/radroots/secrets/services/${serviceName}" 88 "/run/radroots/services/${serviceName}" 89 "/var/lib/radroots/services/${serviceName}" 90 ]; 91 labels = { 92 "dev.radroots.build.feature-profile" = buildInfo.featureProfile; 93 "dev.radroots.build.lib-revision" = buildInfo.libRevision; 94 "dev.radroots.build.rust-version" = buildInfo.rustVersion; 95 "dev.radroots.build.target" = buildInfo.target; 96 "dev.radroots.contract.admin-version" = toString buildInfo.contractVersions.admin; 97 "dev.radroots.contract.config-version" = toString buildInfo.contractVersions.config; 98 "dev.radroots.contract.provider-version" = toString buildInfo.contractVersions.provider; 99 "dev.radroots.contract.state-version" = toString buildInfo.contractVersions.state; 100 "dev.radroots.contract.status-version" = toString buildInfo.contractVersions.status; 101 "dev.radroots.mount.config" = "/etc/radroots/services/${serviceName}"; 102 "dev.radroots.mount.config.mode" = "read-only"; 103 "dev.radroots.mount.credentials" = "/etc/radroots/secrets/services/${serviceName}"; 104 "dev.radroots.mount.credentials.mode" = "read-only"; 105 "dev.radroots.mount.runtime" = "/run/radroots/services/${serviceName}"; 106 "dev.radroots.mount.runtime.mode" = "read-write"; 107 "dev.radroots.mount.state" = "/var/lib/radroots/services/${serviceName}"; 108 "dev.radroots.mount.state.mode" = "read-write"; 109 "dev.radroots.rootfs" = "read-only-compatible"; 110 "org.opencontainers.image.description" = "Hardened ${serviceName} service image"; 111 "org.opencontainers.image.licenses" = package.passthru.radrootsServicePackage.serviceLicense; 112 "org.opencontainers.image.revision" = buildInfo.serviceCommit; 113 "org.opencontainers.image.title" = serviceName; 114 "org.opencontainers.image.version" = buildInfo.serviceVersion; 115 }; 116 in 117 pkgs.dockerTools.buildLayeredImage { 118 name = imageName; 119 tag = buildInfo.serviceVersion; 120 created = "1970-01-01T00:00:01Z"; 121 maxLayers = 2; 122 contents = [ 123 package 124 pkgs.dockerTools.caCertificates 125 ]; 126 config = { 127 User = user; 128 Entrypoint = [ "${package}/bin/${binaryName}" ]; 129 WorkingDir = "/"; 130 Env = [ "SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt" ]; 131 StopSignal = "SIGTERM"; 132 Labels = labels; 133 }; 134 passthru.radrootsServiceOci = { 135 schema = "radroots.service-oci.v1"; 136 schemaVersion = 1; 137 inherit 138 buildInfo 139 imageName 140 labels 141 mountPaths 142 serviceName 143 user 144 ; 145 entrypoint = "${package}/bin/${binaryName}"; 146 }; 147 meta = { 148 description = "Hardened rootless OCI image for ${serviceName}"; 149 platforms = [ 150 "x86_64-linux" 151 ]; 152 }; 153 }