[Nix-dev] [Nix-commits] SVN commit: nix - r30611 - in nixos/trunk/modules: config services/networking/ssh

Nicolas Pierron nicolas.b.pierron at gmail.com
Tue Nov 29 07:14:12 CET 2011


On Tue, Nov 29, 2011 at 07:08, Nicolas Pierron
<nicolas.b.pierron at gmail.com> wrote:
> Author: NicolasPierron
> Date: Tue Nov 29 06:08:55 2011
> New Revision: 30611
> URL: https://nixos.org/websvn/nix/?rev=30611&sc=1
>
> Log:
> Convert users.extraUsers to an option set and add support for openssh
> authorized_keys file generation.

Sorry, I forgot to mention that this patch was contributed by Rickard Nilsson.

Thanks again, for this nice patch.

> Modified:
>   nixos/trunk/modules/config/users-groups.nix
>   nixos/trunk/modules/services/networking/ssh/sshd.nix
>
> Modified: nixos/trunk/modules/config/users-groups.nix
> ==============================================================================
> --- nixos/trunk/modules/config/users-groups.nix Tue Nov 29 05:13:20 2011        (r30610)
> +++ nixos/trunk/modules/config/users-groups.nix Tue Nov 29 06:08:55 2011        (r30611)
> @@ -5,43 +5,83 @@
>  let
>
>   ids = config.ids;
> +  users = config.users;
>
> +  userOpts = {name, config, ...}:
>
> -  # User accounts to be created/updated by NixOS.
> -  users =
> -    let
> -      defaultUsers =
> -        [ { name = "root";
> -            uid = ids.uids.root;
> -            description = "System administrator";
> -            home = "/root";
> -            shell = config.users.defaultUserShell;
> -            group = "root";
> -          }
> -          { name = "nobody";
> -            uid = ids.uids.nobody;
> -            description = "Unprivileged account (don't use!)";
> -          }
> -        ];
> -
> -      # !!! Use NixOS module system to add default attributes.
> -      addAttrs =
> -        { name
> -        , description
> -        , uid ? ""
> -        , group ? "nogroup"
> -        , extraGroups ? []
> -        , home ? "/var/empty"
> -        , shell ? (if useDefaultShell then config.users.defaultUserShell else "/noshell")
> -        , createHome ? false
> -        , useDefaultShell ? false
> -        , password ? null
> -        , isSystemUser ? true
> -        }:
> -        { inherit name description uid group extraGroups home shell createHome password isSystemUser; };
> -
> -    in map addAttrs (defaultUsers ++ config.users.extraUsers);
> +  {
> +    options = {
> +      name = mkOption {
> +        type = with types; uniq string;
> +        description = "The name of the user account. If undefined, the name of the attribute set will be used.";
> +      };
> +      description = mkOption {
> +        type = with types; uniq string;
> +        default = "";
> +        description = "A short description of the user account.";
> +      };
> +      uid = mkOption {
> +        type = with types; uniq (nullOr int);
> +        default = null;
> +        description = "The account UID. If undefined, NixOS will select a UID.";
> +      };
> +      group = mkOption {
> +        type = with types; uniq string;
> +        default = "nogroup";
> +        description = "The user's primary group.";
> +      };
> +      extraGroups = mkOption {
> +        type = types.listOf types.string;
> +        default = [];
> +        description = "The user's auxiliary groups.";
> +      };
> +      home = mkOption {
> +        type = with types; uniq string;
> +        default = "/var/empty";
> +        description = "The user's home directory.";
> +      };
> +      shell = mkOption {
> +        type = with types; uniq string;
> +        default = "/noshell";
> +        description = "The path to the user's shell.";
> +      };
> +      createHome = mkOption {
> +        type = types.bool;
> +        default = false;
> +        description = "If true, the home directory will be created automatically.";
> +      };
> +      useDefaultShell = mkOption {
> +        type = types.bool;
> +        default = false;
> +        description = "If true, the user's shell will be set to <literal>users.defaultUserShell</literal>.";
> +      };
> +      password = mkOption {
> +        type = with types; uniq (nullOr string);
> +        default = null;
> +        description = "The user's password. If undefined, no password is set for the user.  Warning: do not set confidential information here because this data would be readable by all.  This option should only be used for public account such as guest.";
> +      };
> +      isSystemUser = mkOption {
> +        type = types.bool;
> +        default = true;
> +        description = "Indicates if the user is a system user or not.";
> +      };
> +      createUser = mkOption {
> +        type = types.bool;
> +        default = true;
> +        description = "
> +          Indicates if the user should be created automatically as a local user.
> +          Set this to false if the user for instance is an LDAP user. NixOS will
> +          then not modify any of the basic properties for the user account.
> +        ";
> +      };
> +    };
>
> +    config = {
> +      name = mkDefault name;
> +      uid = mkDefault (attrByPath [name] null ids.uids);
> +      shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell);
> +    };
> +  };
>
>   # Groups to be created/updated by NixOS.
>   groups =
> @@ -109,11 +149,14 @@
>
>   # Note: the 'X' in front of the password is to distinguish between
>   # having an empty password, and not having a password.
> -  serializedUser = u: "${u.name}\n${u.description}\n${toString u.uid}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n";
> +  serializedUser = userName: let u = getAttr userName config.users.extraUsers; in "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${if u.createUser then "yes" else "no"}\n";
> +
>   serializedGroup = g: "${g.name}\n${toString g.gid}";
>
>   # keep this extra file so that cat can be used to pass special chars such as "`" which is used in the avahi daemon
> -  usersFile = pkgs.writeText "users" (concatStrings (map serializedUser users));
> +  usersFile = pkgs.writeText "users" (
> +    concatMapStrings serializedUser (attrNames config.users.extraUsers)
> +  );
>
>  in
>
> @@ -124,22 +167,24 @@
>   options = {
>
>     users.extraUsers = mkOption {
> -      default = [];
> -      example =
> -        [ { name = "alice";
> -            uid = 1234;
> -            description = "Alice";
> -            home = "/home/alice";
> -            createHome = true;
> -            group = "users";
> -            extraGroups = ["wheel"];
> -            shell = "/bin/sh";
> -            password = "foobar";
> -          }
> -        ];
> +      default = {};
> +      type = types.loaOf types.optionSet;
> +      example = {
> +        alice = {
> +          uid = 1234;
> +          description = "Alice";
> +          home = "/home/alice";
> +          createHome = true;
> +          group = "users";
> +          extraGroups = ["wheel"];
> +          shell = "/bin/sh";
> +          password = "foobar";
> +        };
> +      };
>       description = ''
>         Additional user accounts to be created automatically by the system.
>       '';
> +      options = [ userOpts ];
>     };
>
>     users.extraGroups = mkOption {
> @@ -154,6 +199,15 @@
>       '';
>     };
>
> +    user = mkOption {
> +      default = {};
> +      description = ''
> +        This option defines settings for individual users on the system.
> +      '';
> +      type = types.loaOf types.optionSet;
> +      options = [ ];
> +    };
> +
>   };
>
>
> @@ -161,6 +215,18 @@
>
>   config = {
>
> +    users.extraUsers = {
> +      root = {
> +        description = "System administrator";
> +        home = "/root";
> +        shell = config.users.defaultUserShell;
> +        group = "root";
> +      };
> +      nobody = {
> +        description = "Unprivileged account (don't use!)";
> +      };
> +    };
> +
>     system.activationScripts.rootPasswd = stringAfter [ "etc" ]
>       ''
>         # If there is no password file yet, create a root account with an
> @@ -192,6 +258,11 @@
>             read createHome
>             read password
>             read isSystemUser
> +            read createUser
> +
> +            if ! test "$createUser" = "yes"; then
> +                continue
> +            fi
>
>             if ! curEnt=$(getent passwd "$name"); then
>                 useradd ''${isSystemUser:+--system} \
>
> Modified: nixos/trunk/modules/services/networking/ssh/sshd.nix
> ==============================================================================
> --- nixos/trunk/modules/services/networking/ssh/sshd.nix        Tue Nov 29 05:13:20 2011        (r30610)
> +++ nixos/trunk/modules/services/networking/ssh/sshd.nix        Tue Nov 29 06:08:55 2011        (r30611)
> @@ -14,6 +14,98 @@
>     v == "forced-commands-only" ||
>     v == "no";
>
> +  userOptions = {
> +    openssh.authorizedKeys = {
> +
> +      preserveExistingKeys = mkOption {
> +        type = types.bool;
> +        default = true;
> +        description = ''
> +          If this option is enabled, the keys specified in
> +          <literal>keys</literal> and/or <literal>keyFiles</literal> will be
> +          placed in a special section of the user's authorized_keys file
> +          and any existing keys will be preserved. That section will be
> +          regenerated each time NixOS is activated. However, if
> +          <literal>preserveExisting</literal> isn't enabled, the complete file
> +          will be generated, and any user modifications will be wiped out.
> +        '';
> +      };
> +
> +      keys = mkOption {
> +        type = types.listOf types.string;
> +        default = [];
> +        description = ''
> +          A list of verbatim OpenSSH public keys that should be inserted into the
> +          user's authorized_keys file. You can combine the <literal>keys</literal> and
> +          <literal>keyFiles</literal> options.
> +        '';
> +      };
> +
> +      keyFiles = mkOption {
> +        type = types.listOf types.string;
> +        default = [];
> +        description = ''
> +          A list of files each containing one OpenSSH public keys that should be
> +          inserted into the user's authorized_keys file. You can combine
> +          the <literal>keyFiles</literal> and
> +          <literal>keys</literal> options.
> +        '';
> +      };
> +
> +    };
> +  };
> +
> +  mkAuthkeyScript =
> +    let
> +      marker1 = "### NixOS will regenerate this line and every line below it.";
> +      marker2 = "### NixOS will regenerate this file. Do not edit!";
> +      users = map (userName: getAttr userName config.users.extraUsers) (attrNames config.users.extraUsers);
> +      usersWithKeys = flip filter users (u:
> +        length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0
> +      );
> +      userLoop = flip concatMapStrings usersWithKeys (u:
> +        let
> +          authKeys = concatStringsSep "," u.openssh.authorizedKeys.keys;
> +          authKeyFiles = concatStringsSep "," u.openssh.authorizedKeys.keyFiles;
> +          preserveExisting = if u.openssh.authorizedKeys.preserveExistingKeys then "true" else "false";
> +        in ''
> +          mkAuthKeysFile "${u.name}" "${authKeys}" "${authKeyFiles}" "${preserveExisting}"
> +        ''
> +      );
> +    in ''
> +      mkAuthKeysFile() {
> +        local userName="$1"
> +        local authKeys="$2"
> +        local authKeyFiles="$3"
> +        local preserveExisting="$4"
> +        IFS=","
> +
> +        for f in $authKeyFiles; do
> +          if [ -f "$f" ]; then
> +            authKeys="$(${pkgs.coreutils}/bin/cat "$f"),$authKeys"
> +          fi
> +        done
> +
> +        if [ -n "$authKeys" ]; then
> +          eval authfile=~$userName/.ssh/authorized_keys
> +          ${pkgs.coreutils}/bin/mkdir -p "$(dirname $authfile)"
> +          ${pkgs.coreutils}/bin/touch "$authfile"
> +          if [ "$preserveExisting" == "false" ]; then
> +            rm -f "$authfile"
> +            authKeys="${marker2},$authKeys"
> +          else
> +            ${pkgs.gnused}/bin/sed -i '/^### NixOS.*$/,$d' "$authfile"
> +            authKeys="${marker1},$authKeys"
> +          fi
> +          for key in $authKeys; do ${pkgs.coreutils}/bin/echo "$key" >> "$authfile"; done
> +        fi
> +
> +        unset IFS
> +      }
> +      ${userLoop}
> +    '';
> +
> +
>  in
>
>  {
> @@ -102,6 +194,10 @@
>
>     };
>
> +    users.extraUsers = mkOption {
> +      options = [ userOptions ];
> +    };
> +
>   };
>
>
> @@ -135,6 +231,8 @@
>
>         preStart =
>           ''
> +            ${mkAuthkeyScript}
> +
>             mkdir -m 0755 -p /etc/ssh
>
>             if ! test -f /etc/ssh/ssh_host_dsa_key; then
> _______________________________________________
> nix-commits mailing list
> nix-commits at lists.science.uu.nl
> http://lists.science.uu.nl/mailman/listinfo/nix-commits
>



-- 
Nicolas Pierron
http://www.linkedin.com/in/nicolasbpierron - http://nbp.name/


More information about the nix-dev mailing list