This question already has an answer here:

I've configured several systems manually. I'd like to start working more systematically now.

I configure openssh-server more strictly than Debian defaults, to exclude password-guessing attacks.

So I worked on some sequences for system configuration. I notice SSH is a problem. When you install openssh-server on Debian, it immediately starts running with the default configuration (unlike Fedora).

Question: suggest a sequence for securely configuring SSH which avoids this race condition.

E.g. I want to use SSH on one desktop system, where other users have never needed SSH access. They don't use any remote access to the system. Working to enforce "secure passwords" would waste our time. Limiting remote access in /etc/sshd_config is simpler and better security.

I have also sometimes created local accounts for test purposes. (Embarrassingly, I had one such account fall victim to an SSH worm).

marked as duplicate by sourcejedi, Community Nov 26 '18 at 10:47

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • Thanks, that was interesting. In pt 1. of my answer I explain why preventing service start is not enough on its own, so I request that my question not be considered a duplicate. – sourcejedi Nov 7 '16 at 13:33


  1. Create an empty file /etc/ssh/sshd_not_to_be_run, if openssh-server is not installed. (Some options for scripting this condition here)
  2. Install openssh-server
  3. Edit /etc/ssh/sshd_config as desired
  4. Remove /etc/ssh/sshd_not_to_be_run

  5. Run

    systemctl enable ssh
    systemctl systemctl restart ssh

    or a well-tested equivalent. restart appears to work ok if the service wasn't already started (compare condrestart try-restart). I notice systemctl enable --now does not start the service, if it was already enabled but not running.

Options which were not used

These are the other options I discovered and decided not to use.

  1. This issue has been discussed at debian-users. Sadly the race condition is not solved. A Debian maintainer suggests configuring policy-rc.d to block the invoke-rc.d ssh start call in the package postinstall. There are clunky details details are clunky, but achievable. Unfortunately this is not really true; it doesn't prevent a race condition. policy-rc.d is not relevant to the update-rc.d ssh enable command which the package also runs. This would be exposed by a power failure or system crash at the wrong time.

  2. Notice the openssh-server package suggests ufw :). Ubuntu created ufw as a very simple firewall. I'm somewhat puzzled what "user stories" it was originally written for, but in Ubuntu Oneiric it's used to support a concept of trusted networks, like Windows does.

    You could install ufw and abuse it to block SSH until you've configured it. Of course this assumes there isn't a configuration where ufw treats the current network as trusted. Heh.

    I dislike this option for two further reasons. I've been writing sequences as individual ansible roles. Firstly, this option means an SSH role is messing with firewall configuration. Even when the host didn't otherwise need a firewall. (Or if you're writing these sequences incrementally... and perhaps you have an existing firewall which doesn't even have commands like ufw does which are so convenient for automation).

    A second wart is that ansible roles are designed to be idempotent. You can update your ansible roles and run a single command to apply them all. It will highlight the tasks that actually changed the system v.s. those that already matched. You make restarting services conditional on whether their configuration was modified (as opposed to already matching). It doesn't fit the model to unconditionally toggle the firewall configuration on & off. You could make this conditional on openssh-server not being installed already, but that's not one of the common idioms you see in the documentation examples. You either need ansible 2.2, to apply check_mode: yes to service name=ssh, or you need to script around dpkg.

  3. EDIT: You can just create a symlink to mask ssh.service, before installing the package. I don't mind assuming systemd is used , however automating this would be somewhat annoying. I think the package install would return an error, and leave the package installed but with a state of "unconfigured". It's not hard to "reconfigure" the package after fixing the config. The annoyance is that you have to ignore the error during the package install. You risk continuing when there might have been another error. It's particularly a problem for proper automation, but it can also be annoying if you're following a manual checklist.

  4. Create an sshd_config in advance. I tested this and it was not overwritten. Problem: the packaged sshd_config was nowhere to be seen. (I tried this on Fedora as well - they give you a warning and creates sshd_config.rpmnew). If you wanted to base your config on the packaged configuration... it becomes complex even if the package didn't lose its file.

  5. One of the answers linked to by @Ipor-Sircer points out that Debian can be monkey-patched using dpkg-divert. debootstrap uses this on start-stop-daemon. We could divert update-rc.d, in combination with option 1. Now we're writing two temporary scripts...

  6. Less intrusively, we could try to use it to divert the installation of /etc/sshd_config. This would allow preserving the packaged config file for inspection, and by explicitly preventing the overwrite it might be more robust. Unfortunately it turns out dpkg-divert doesn't affect sshd_config, because the file is dynamically generated by a postinstall script. This probably explains the lack of a warning in option 5.

The last point was explained to me by someone who pointed at the package source code. I then noticed a reference to sshd_not_to_be_run in the postrm script.

Not the answer you're looking for? Browse other questions tagged or ask your own question.