summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/cluster/kubernetes.nix106
-rw-r--r--nixos/modules/services/misc/mwlib.nix2
-rw-r--r--nixos/modules/services/misc/ripple-rest.nix110
-rw-r--r--nixos/modules/services/networking/consul.nix181
-rw-r--r--nixos/modules/services/networking/skydns.nix91
5 files changed, 373 insertions, 117 deletions
diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix
index 6a775bb159fc..a7f4ec7b008b 100644
--- a/nixos/modules/services/cluster/kubernetes.nix
+++ b/nixos/modules/services/cluster/kubernetes.nix
@@ -286,7 +286,7 @@ in {
 
       clusterDomain = mkOption {
         description = "Use alternative domain.";
-        default = "";
+        default = "kubernetes.io";
         type = types.str;
       };
 
@@ -322,13 +322,35 @@ in {
         type = types.str;
       };
     };
+
+    kube2sky = {
+      enable = mkEnableOption "Whether to enable kube2sky dns service.";
+
+      domain = mkOption  {
+        description = "Kuberntes kube2sky domain under which all DNS names will be hosted.";
+        default = cfg.kubelet.clusterDomain;
+        type = types.str;
+      };
+
+      master = mkOption {
+        description = "Kubernetes apiserver address";
+        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
+        type = types.str;
+      };
+
+      extraOpts = mkOption {
+        description = "Kubernetes kube2sky extra command line options.";
+        default = "";
+        type = types.str;
+      };
+    };
   };
 
   ###### implementation
 
   config = mkMerge [
     (mkIf cfg.apiserver.enable {
-      systemd.services.kubernetes-apiserver = {
+      systemd.services.kube-apiserver = {
         description = "Kubernetes Api Server";
         wantedBy = [ "multi-user.target" ];
         requires = ["kubernetes-setup.service"];
@@ -343,26 +365,25 @@ in {
                 (concatImapStringsSep "\n" (i: v: v + "," + (toString i))
                     (mapAttrsToList (name: token: token + "," + name) cfg.apiserver.tokenAuth));
           in ''${cfg.package}/bin/kube-apiserver \
-            --etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \
-            --address=${cfg.apiserver.address} \
-            --port=${toString cfg.apiserver.port} \
-            --read_only_port=${toString cfg.apiserver.readOnlyPort} \
-            --public_address_override=${cfg.apiserver.publicAddress} \
-            --allow_privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \
+            --etcd-servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \
+            --insecure-bind-address=${cfg.apiserver.address} \
+            --insecure-port=${toString cfg.apiserver.port} \
+            --read-only-port=${toString cfg.apiserver.readOnlyPort} \
+            --bind-address=${cfg.apiserver.publicAddress} \
+            --allow-privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \
             ${optionalString (cfg.apiserver.tlsCertFile!="")
-              "--tls_cert_file=${cfg.apiserver.tlsCertFile}"} \
+              "--tls-cert-file=${cfg.apiserver.tlsCertFile}"} \
             ${optionalString (cfg.apiserver.tlsPrivateKeyFile!="")
-              "--tls_private_key_file=${cfg.apiserver.tlsPrivateKeyFile}"} \
+              "--tls-private-key-file=${cfg.apiserver.tlsPrivateKeyFile}"} \
             ${optionalString (cfg.apiserver.tokenAuth!=[])
-              "--token_auth_file=${tokenAuthFile}"} \
-            --authorization_mode=${cfg.apiserver.authorizationMode} \
+              "--token-auth-file=${tokenAuthFile}"} \
+            --authorization-mode=${cfg.apiserver.authorizationMode} \
             ${optionalString (cfg.apiserver.authorizationMode == "ABAC")
-              "--authorization_policy_file=${authorizationPolicyFile}"} \
-            --secure_port=${toString cfg.apiserver.securePort} \
-            --portal_net=${cfg.apiserver.portalNet} \
+              "--authorization-policy-file=${authorizationPolicyFile}"} \
+            --secure-port=${toString cfg.apiserver.securePort} \
+            --service-cluster-ip-range=${cfg.apiserver.portalNet} \
             --logtostderr=true \
-            --runtime_config=api/v1beta3 \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.apiserver.extraOpts}
           '';
           User = "kubernetes";
@@ -376,7 +397,7 @@ in {
     })
 
     (mkIf cfg.scheduler.enable {
-      systemd.services.kubernetes-scheduler = {
+      systemd.services.kube-scheduler = {
         description = "Kubernetes Scheduler Service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
@@ -386,7 +407,7 @@ in {
             --port=${toString cfg.scheduler.port} \
             --master=${cfg.scheduler.master} \
             --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.scheduler.extraOpts}
           '';
           User = "kubernetes";
@@ -395,7 +416,7 @@ in {
     })
 
     (mkIf cfg.controllerManager.enable {
-      systemd.services.kubernetes-controller-manager = {
+      systemd.services.kube-controller-manager = {
         description = "Kubernetes Controller Manager Service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
@@ -406,7 +427,7 @@ in {
             --master=${cfg.controllerManager.master} \
             --machines=${concatStringsSep "," cfg.controllerManager.machines} \
             --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.controllerManager.extraOpts}
           '';
           User = "kubernetes";
@@ -415,7 +436,7 @@ in {
     })
 
     (mkIf cfg.kubelet.enable {
-      systemd.services.kubernetes-kubelet = {
+      systemd.services.kubelet = {
         description = "Kubernetes Kubelet Service";
         wantedBy = [ "multi-user.target" ];
         requires = ["kubernetes-setup.service"];
@@ -423,17 +444,17 @@ in {
         script = ''
           export PATH="/bin:/sbin:/usr/bin:/usr/sbin:$PATH"
           exec ${cfg.package}/bin/kubelet \
-            --api_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.kubelet.apiServers}  \
+            --api-servers=${concatMapStringsSep "," (f: "http://${f}") cfg.kubelet.apiServers}  \
             --address=${cfg.kubelet.address} \
             --port=${toString cfg.kubelet.port} \
-            --hostname_override=${cfg.kubelet.hostname} \
-            --allow_privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \
-            --root_dir=${cfg.dataDir} \
+            --hostname-override=${cfg.kubelet.hostname} \
+            --allow-privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \
+            --root-dir=${cfg.dataDir} \
             --cadvisor_port=${toString cfg.kubelet.cadvisorPort} \
             ${optionalString (cfg.kubelet.clusterDns != "")
-                ''--cluster_dns=${cfg.kubelet.clusterDns}''} \
+                ''--cluster-dns=${cfg.kubelet.clusterDns}''} \
             ${optionalString (cfg.kubelet.clusterDomain != "")
-                ''--cluster_domain=${cfg.kubelet.clusterDomain}''} \
+                ''--cluster-domain=${cfg.kubelet.clusterDomain}''} \
             --logtostderr=true \
             ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
             ${cfg.kubelet.extraOpts}
@@ -443,26 +464,49 @@ in {
     })
 
     (mkIf cfg.proxy.enable {
-      systemd.services.kubernetes-proxy = {
+      systemd.services.kube-proxy = {
         description = "Kubernetes Proxy Service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network-interfaces.target" "etcd.service" ];
         serviceConfig = {
           ExecStart = ''${cfg.package}/bin/kube-proxy \
             --master=${cfg.proxy.master} \
-            --bind_address=${cfg.proxy.address} \
+            --bind-address=${cfg.proxy.address} \
             --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
             ${cfg.proxy.extraOpts}
           '';
         };
       };
     })
 
+    (mkIf cfg.kube2sky.enable {
+      systemd.services.kube2sky = {
+        description = "Kubernetes Dns Bridge Service";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" "skydns.service" "etcd.service" "kubernetes-apiserver.service" ];
+        serviceConfig = {
+          ExecStart = ''${cfg.package}/bin/kube2sky \
+            -etcd-server=http://${head cfg.etcdServers} \
+            -domain=${cfg.kube2sky.domain} \
+            -kube_master_url=http://${cfg.kube2sky.master} \
+            -logtostderr=true \
+            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
+            ${cfg.kube2sky.extraOpts}
+          '';
+          User = "kubernetes";
+        };
+      };
+
+      services.skydns.enable = mkDefault true;
+      services.skydns.domain = mkDefault cfg.kubelet.clusterDomain;
+    })
+
     (mkIf (any (el: el == "master") cfg.roles) {
       services.kubernetes.apiserver.enable = mkDefault true;
       services.kubernetes.scheduler.enable = mkDefault true;
       services.kubernetes.controllerManager.enable = mkDefault true;
+      services.kubernetes.kube2sky.enable = mkDefault true;
     })
 
     (mkIf (any (el: el == "node") cfg.roles) {
diff --git a/nixos/modules/services/misc/mwlib.nix b/nixos/modules/services/misc/mwlib.nix
index d02e1e021a70..a8edecff2a1e 100644
--- a/nixos/modules/services/misc/mwlib.nix
+++ b/nixos/modules/services/misc/mwlib.nix
@@ -226,7 +226,7 @@ in
         chmod -Rc u=rwX,go= '${cfg.nslave.cachedir}'
       '';
 
-      path = with pkgs; [ imagemagick ];
+      path = with pkgs; [ imagemagick pdftk ];
       environment = {
         PYTHONPATH = concatMapStringsSep ":"
           (m: "${pypkgs.${m}}/lib/${python.libPrefix}/site-packages")
diff --git a/nixos/modules/services/misc/ripple-rest.nix b/nixos/modules/services/misc/ripple-rest.nix
new file mode 100644
index 000000000000..dc07ee132fa6
--- /dev/null
+++ b/nixos/modules/services/misc/ripple-rest.nix
@@ -0,0 +1,110 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.rippleRest;
+
+  configFile = pkgs.writeText "ripple-rest-config.json" (builtins.toJSON {
+    config_version = "2.0.3";
+    debug = cfg.debug;
+    port = cfg.port;
+    host = cfg.host;
+    ssl_enabled = cfg.ssl.enable;
+    ssl = {
+      key_path = cfg.ssl.keyPath;
+      cert_path = cfg.ssl.certPath;
+      reject_unathorized = cfg.ssl.rejectUnathorized;
+    };
+    db_path = cfg.dbPath;
+    max_transaction_fee = cfg.maxTransactionFee;
+    rippled_servers = cfg.rippleds;
+  });
+
+in {
+  options.services.rippleRest = {
+    enable = mkEnableOption "Whether to enable ripple rest.";
+
+    debug = mkEnableOption "Wheter to enable debug for ripple-rest.";
+
+    host = mkOption {
+      description = "Ripple rest host.";
+      default = "localhost";
+      type = types.str;
+    };
+
+    port = mkOption {
+      description = "Ripple rest port.";
+      default = 5990;
+      type = types.int;
+    };
+
+    ssl = {
+      enable = mkEnableOption "Whether to enable ssl.";
+
+      keyPath = mkOption {
+        description = "Path to the ripple rest key file.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+
+      certPath = mkOption {
+        description = "Path to the ripple rest cert file.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      rejectUnathorized = mkOption {
+        description = "Whether to reject unatohroized.";
+        default = true;
+        type = types.bool;
+      };
+    };
+
+    dbPath = mkOption {
+      description = "Ripple rest database path.";
+      default = "${cfg.dataDir}/ripple-rest.db";
+      type = types.path;
+    };
+
+    maxTransactionFee = mkOption {
+      description = "Ripple rest max transaction fee.";
+      default = 1000000;
+      type = types.int;
+    };
+
+    rippleds = mkOption {
+      description = "List of rippled servers.";
+      default = [
+        "wss://s1.ripple.com:443"
+      ];
+      type = types.listOf types.str;
+    };
+
+    dataDir = mkOption {
+      description = "Ripple rest data directory.";
+      default = "/var/lib/ripple-rest";
+      type = types.path;
+    };
+  };
+
+  config = mkIf (cfg.enable) {
+    systemd.services.ripple-rest = {
+      wantedBy = [ "multi-user.target"];
+      after = ["network.target" ];
+      environment.NODE_PATH="${pkgs.ripple-rest}/lib/node_modules/ripple-rest/node_modules";
+      serviceConfig = {
+        ExecStart = "${pkgs.nodejs}/bin/node ${pkgs.ripple-rest}/lib/node_modules/ripple-rest/server/server.js --config ${configFile}";
+        User = "ripple-rest";
+      };
+    };
+
+    users.extraUsers.postgres = {
+      name = "ripple-rest";
+      uid = config.ids.uids.ripple-rest;
+      createHome = true;
+      home = cfg.dataDir;
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 53a9f4626254..31bae628050b 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -106,6 +106,12 @@ in
       alerts = {
         enable = mkEnableOption "Whether to enable consul-alerts";
 
+        package = mkOption {
+          description = "Package to use for consul-alerts.";
+          default = pkgs.consul-alerts;
+          type = types.package;
+        };
+
         listenAddr = mkOption {
           description = "Api listening address.";
           default = "localhost:9000";
@@ -135,96 +141,101 @@ in
 
   };
 
-  config = mkIf cfg.enable {
+  config = mkIf cfg.enable (
+    mkMerge [{
 
-    users.extraUsers."consul" = {
-      description = "Consul agent daemon user";
-      uid = config.ids.uids.consul;
-      # The shell is needed for health checks
-      shell = "/run/current-system/sw/bin/bash";
-    };
+      users.extraUsers."consul" = {
+        description = "Consul agent daemon user";
+        uid = config.ids.uids.consul;
+        # The shell is needed for health checks
+        shell = "/run/current-system/sw/bin/bash";
+      };
 
-    environment = {
-      etc."consul.json".text = builtins.toJSON configOptions;
-      # We need consul.d to exist for consul to start
-      etc."consul.d/dummy.json".text = "{ }";
-      systemPackages = with pkgs; [ consul ];
-    };
+      environment = {
+        etc."consul.json".text = builtins.toJSON configOptions;
+        # We need consul.d to exist for consul to start
+        etc."consul.d/dummy.json".text = "{ }";
+        systemPackages = with pkgs; [ consul ];
+      };
 
-    systemd.services.consul = {
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ] ++ systemdDevices;
-      bindsTo = systemdDevices;
-      restartTriggers = [ config.environment.etc."consul.json".source ]
-        ++ mapAttrsToList (_: d: d.source)
-          (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc);
-
-      serviceConfig = {
-        ExecStart = "@${pkgs.consul}/bin/consul consul agent -config-dir /etc/consul.d"
-          + concatMapStrings (n: " -config-file ${n}") configFiles;
-        ExecReload = "${pkgs.consul}/bin/consul reload";
-        PermissionsStartOnly = true;
-        User = if cfg.dropPrivileges then "consul" else null;
-        TimeoutStartSec = "0";
-      } // (optionalAttrs (cfg.leaveOnStop) {
-        ExecStop = "${pkgs.consul}/bin/consul leave";
-      });
-
-      path = with pkgs; [ iproute gnugrep gawk consul ];
-      preStart = ''
-        mkdir -m 0700 -p ${dataDir}
-        chown -R consul ${dataDir}
-
-        # Determine interface addresses
-        getAddrOnce () {
-          ip addr show dev "$1" \
-            | grep 'inet${optionalString (cfg.forceIpv4) " "}.*scope global' \
-            | awk -F '[ /\t]*' '{print $3}' | head -n 1
-        }
-        getAddr () {
-          ADDR="$(getAddrOnce $1)"
-          LEFT=60 # Die after 1 minute
-          while [ -z "$ADDR" ]; do
-            sleep 1
-            LEFT=$(expr $LEFT - 1)
-            if [ "$LEFT" -eq "0" ]; then
-              echo "Address lookup timed out"
-              exit 1
-            fi
+      systemd.services.consul = {
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ] ++ systemdDevices;
+        bindsTo = systemdDevices;
+        restartTriggers = [ config.environment.etc."consul.json".source ]
+          ++ mapAttrsToList (_: d: d.source)
+            (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc);
+
+        serviceConfig = {
+          ExecStart = "@${pkgs.consul}/bin/consul consul agent -config-dir /etc/consul.d"
+            + concatMapStrings (n: " -config-file ${n}") configFiles;
+          ExecReload = "${pkgs.consul}/bin/consul reload";
+          PermissionsStartOnly = true;
+          User = if cfg.dropPrivileges then "consul" else null;
+          TimeoutStartSec = "0";
+        } // (optionalAttrs (cfg.leaveOnStop) {
+          ExecStop = "${pkgs.consul}/bin/consul leave";
+        });
+
+        path = with pkgs; [ iproute gnugrep gawk consul ];
+        preStart = ''
+          mkdir -m 0700 -p ${dataDir}
+          chown -R consul ${dataDir}
+
+          # Determine interface addresses
+          getAddrOnce () {
+            ip addr show dev "$1" \
+              | grep 'inet${optionalString (cfg.forceIpv4) " "}.*scope global' \
+              | awk -F '[ /\t]*' '{print $3}' | head -n 1
+          }
+          getAddr () {
             ADDR="$(getAddrOnce $1)"
-          done
-          echo "$ADDR"
-        }
-        echo "{" > /etc/consul-addrs.json
-        delim=" "
-      ''
-      + concatStrings (flip mapAttrsToList cfg.interface (name: i:
-        optionalString (i != null) ''
-          echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json
-          delim=","
-        ''))
-      + ''
-        echo "}" >> /etc/consul-addrs.json
-      '';
-    };
-
-    systemd.services.consul-alerts = mkIf (cfg.alerts.enable) {
-      wantedBy = [ "multi-user.target" ];
-      after = [ "consul.service" ];
-
-      path = [ pkgs.consul ];
-
-      serviceConfig = {
-        ExecStart = ''
-          ${pkgs.consul-alerts}/bin/consul-alerts start \
-            --alert-addr=${cfg.alerts.listenAddr} \
-            --consul-addr=${cfg.alerts.consulAddr} \
-            ${optionalString cfg.alerts.watchChecks "--watch-checks"} \
-            ${optionalString cfg.alerts.watchEvents "--watch-events"}
+            LEFT=60 # Die after 1 minute
+            while [ -z "$ADDR" ]; do
+              sleep 1
+              LEFT=$(expr $LEFT - 1)
+              if [ "$LEFT" -eq "0" ]; then
+                echo "Address lookup timed out"
+                exit 1
+              fi
+              ADDR="$(getAddrOnce $1)"
+            done
+            echo "$ADDR"
+          }
+          echo "{" > /etc/consul-addrs.json
+          delim=" "
+        ''
+        + concatStrings (flip mapAttrsToList cfg.interface (name: i:
+          optionalString (i != null) ''
+            echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json
+            delim=","
+          ''))
+        + ''
+          echo "}" >> /etc/consul-addrs.json
         '';
-        User = if cfg.dropPrivileges then "consul" else null;
       };
-    };
+    }
+
+    (mkIf (cfg.alerts.enable) {
+      systemd.services.consul-alerts = {
+        wantedBy = [ "multi-user.target" ];
+        after = [ "consul.service" ];
+
+        path = [ pkgs.consul ];
+
+        serviceConfig = {
+          ExecStart = ''
+            ${cfg.alerts.package}/bin/consul-alerts start \
+              --alert-addr=${cfg.alerts.listenAddr} \
+              --consul-addr=${cfg.alerts.consulAddr} \
+              ${optionalString cfg.alerts.watchChecks "--watch-checks"} \
+              ${optionalString cfg.alerts.watchEvents "--watch-events"}
+          '';
+          User = if cfg.dropPrivileges then "consul" else null;
+          Restart = "on-failure";
+        };
+      };
+    })
 
-  };
+  ]);
 }
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
new file mode 100644
index 000000000000..2d0129d63101
--- /dev/null
+++ b/nixos/modules/services/networking/skydns.nix
@@ -0,0 +1,91 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.skydns;
+
+in {
+  options.services.skydns = {
+    enable = mkEnableOption "Whether to enable skydns service.";
+
+    etcd = {
+      machines = mkOption {
+        default = [ "http://localhost:4001" ];
+        type = types.listOf types.str;
+        description = "Skydns list of etcd endpoints to connect to.";
+      };
+
+      tlsKey = mkOption {
+        default = null;
+        type = types.nullOr types.path;
+        description = "Skydns path of TLS client certificate - private key.";
+      };
+
+      tlsPem = mkOption {
+        default = null;
+        type = types.nullOr types.path;
+        description = "Skydns path of TLS client certificate - public key.";
+      };
+
+      caCert = mkOption {
+        default = null;
+        type = types.nullOr types.path;
+        description = "Skydns path of TLS certificate authority public key.";
+      };
+    };
+
+    address = mkOption {
+      default = "0.0.0.0:53";
+      type = types.str;
+      description = "Skydns address to bind to.";
+    };
+
+    domain = mkOption {
+      default = "skydns.local.";
+      type = types.str;
+      description = "Skydns default domain if not specified by etcd config.";
+    };
+
+    nameservers = mkOption {
+      default = map (n: n + ":53") config.networking.nameservers;
+      type = types.listOf types.str;
+      description = "Skydns list of nameservers to forward DNS requests to when not authoritative for a domain.";
+      example = ["8.8.8.8:53" "8.8.4.4:53"];
+    };
+
+    package = mkOption {
+      default = pkgs.goPackages.skydns;
+      type = types.package;
+      description = "Skydns package to use.";
+    };
+
+    extraConfig = mkOption {
+      default = {};
+      type = types.attrsOf types.str;
+      description = "Skydns attribute set of extra config options passed as environemnt variables.";
+    };
+  };
+
+  config = mkIf (cfg.enable) {
+    systemd.services.skydns = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "etcd.service" ];
+      description = "Skydns Service";
+      environment = {
+        ETCD_MACHINES = concatStringsSep "," cfg.etcd.machines;
+        ETCD_TLSKEY = cfg.etcd.tlsKey;
+        ETCD_TLSPEM = cfg.etcd.tlsPem;
+        ETCD_CACERT = cfg.etcd.caCert;
+        SKYDNS_ADDR = cfg.address;
+        SKYDNS_DOMAIN = cfg.domain;
+        SKYDNS_NAMESERVER = concatStringsSep "," cfg.nameservers;
+      };
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/skydns";
+      };
+    };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}