I'm trying to force users logging in through SSH to have a shell inside IP namespace.

I've tried replacing the shell in /etc/passwd with something like ip netns exec sshns /bin/bash but it didn't work.

Any other ideas? Is it possible at all? Would it be secure or not at all?

  • Simply disable all but ssh access, like telnet, rlogin and other r-stuff – ott-- Oct 24 '15 at 20:43
  • I want to do it only for particular users. Not system-wide. That's why I asked how to run user's shell in ip namespace. – Marcin Krupowicz Oct 24 '15 at 20:47

The problem with handling this by changing login shell, as in your example, is that when user connects to sshd in the main network namespace then even if you get their shell to run inside another namespace but their port forwarding will operate in the default network namespace anyway.

My proposed solution also addresses containing port forwarding to the namespace as well as the shell. It is probably limited to using local accounts, as authenticating against remote system over the network (NIS, SMB etc) will probably not work because authentication stage will be executed from within the network namespace.

I needed both the shell and port forwarding to operate in the target namespace without creating networking/routing between default and contained namespaces.

Here are a few methods/tools to achieve this:

xinetd - Thanks Stéphane Chazelas for pointing it out. For a single or static number of namespaces and forwarding to them xinetd seems a better option. e.g. file /etc/xinetd.d/sshd-netns-foo

service sshdnetns
    type            = UNLISTED
    socket_type     = stream
    protocol        = tcp
    port            = 222
    wait            = no
    user            = root
    server          = /sbin/ip
    server_args     = netns exec NameSpaceName /usr/sbin/sshd -i

socat - for multiple namespaces where forwarding to them needs to be started/stopped independently socat is a good fit. Run this in the default namespace:

socat tcp-listen:222,fork,reuseaddr \
      exec:'ip netns exec NameSpaceName /usr/sbin/sshd -i',nofork

ncat - if socat is not available then ncat (on my RHEL box as nc) can do the job. Downside with ncat is the sshd is connected to ncat via a pipe rather than directly to the socket so sshd can not see client IP with all following consequences. You also end up running on extra intermediate ncat process.

ncat --keep-open --sh-exec "exec ip netns exec NameSpaceName /usr/sbin/sshd -i" -l 222

and probably other tools.

This accepts SSH connections in the default namespace on a custom port 222 and for each connection starts one time sshd -i inside the target namespace.

That solved it for me, but you also have a requirement of limiting users that can login to each namespace. Create a namespace specific sshd config:

mkdir -pv /etc/netns/NameSpaceName/
cp -Rp /etc/ssh /etc/netns/NameSpaceName/

Add access controls to each sshd_config file, e.g. in default /etc/ssh/sshd_config:

AllowUsers user1 user2

... and in /etc/netns/NameSpaceName/ssh/sshd_config

AllowUsers restrictedUser1 restrictedUser2

... also look at AllowGroups directives

now re-create the namespace for the dir binds to become effective

My brief tests show user access control works as expected, but I have not really used it much so its is for you to validate.

I tried putting separate /etc/passwd, /etc/shadow and /etc/group files into /etc/netns/NameSpaceName/ for having separate list of users, but in my quick test that did not work: useradd test inside the namespace fails.


If you don't like custom port you could dual home e.g. macvlan or just add another IP address and listen on the default port on a dedicated IP.

All authentication, shell, subsystem, port forwarding etc is handled by the sshd so I don't have to hack anything else.

It does have drawback of running sshd -i like this, read man sshd look for -i option. You could easily solve it by running a full time sshd inside the namespace and change the forwarding daemon to something like this:

nc --keep-open --sh-exec "exec ip netns exec NameSpaceName nc localhost 22" -l 222

I wonder if mount and/or user namespaces (in addition to network namespaces) could be used to solve it more neatly. I have no experience with those.

There probably are better ways to achieve this, I'd be very interested in what others come up with.

| improve this answer | |
  • 1
    👍 You can also use inetd/xinetd here to avoid having to start a nc/socat as a daemon. – Stéphane Chazelas Jul 15 '16 at 8:19
  • @Stéphane Chazelas, yes, certainly. In my case I was running the daemon under systemd templated service with multiple name spaces and forwarding to them, so for me ncat made process of starting/stopping individual services easier, but static forwarding or a single namespace xinetd would make more sense. it is worth an edit to include it in the solution. – AnyDev Jul 15 '16 at 8:23

You can only set a user's shell to the full pathname of a single command, with no args.

If you want to run multiple commands or commands with args then write a shell script, make it executable, and set the user's shell to the script.


printf '#!/bin/sh\n%s\n' 'exec ip netns exec sshns /bin/bash "$@"' > /usr/local/bin/myshell.sh
chmod a+rx /usr/local/bin/myshell.sh
chsh -u user -s /usr/local/bin/myshell.sh

I have no idea if ip netns exec sshns /bin/bash will work or not. I haven't tested that - it doesn't look like a valid command to me, but assuming it's a valid command or you can come up with one that is, using a shell script as a user's shell will work, i tested it with just exec /usr/bin/zsh in the script.

| improve this answer | |
  • About multiple commands - agree. I've tried and it doesn't work probably because ip netns can be run only as root. Maybe there is some option in OpenSSH? – Marcin Krupowicz Oct 25 '15 at 9:06
  • 1
    I have no idea, but then I have no idea what it is you actually want to achieve. Try updating your question with an explanation of what you mean by how to run user's shell in ip namespace. I can't parse any meaning out of that. – cas Oct 25 '15 at 9:11
  • 1
    I think the question would be clear if you knew that "ip netns exec sshns /bin/bash" was a valid command and you knew it does. I want user to have a shell in protected (ip-namespaced) environment. For that ip namespace I have defined firewall rules. – Marcin Krupowicz Oct 25 '15 at 10:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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