I am deploying an Nodejs Express app. It is going to run as on the same box as an Nginx server, which will proxy requests to it via a unix socket. The question is not specific to Nodejs, however.
The express app runs as user nodejs
, and nginx runs as nginx
.
My plan is to create a /sockets
directory owned by nodejs
for Express to put sockets in, and to grant nginx
access to those sockets via a default ACL on the directory. Feel free to tell me if this is a silly idea, but keep in mind that's not my core question.
I create ACLs on the directory by running, as root,
setfacl -Rd --mask -m nginx:rw /sockets
setfacl -R --mask -m nginx:rwX /sockets
The directory then has the following ACLs: (tabulation by me for legibility in the question)
# file: /sockets
# owner: nodejs
# group: root
user: : rwx
user: nginx: rwx
group: : r-x
mask: : rwx
other: : r-x
default: user: :rwx
default: user:nginx:rw-
default:group: :r-x
default: mask: :rwx
default:other: :r-x
If, running as nodejs
, I write to a file, it is created appropriately:
sudo -su nodejs
touch /sockets/testFile
getfacl /sockets/testFile
# file: /sockets/testFile
# owner: nodejs
# group: nodejs
user: :rw-
user:nginx:rw-
group: :r-x #effective:r--
mask: :rw-
other: :r--
Great!
However, if Node creates a socket by calling listen()
on a path in this directory , it is created with an ACL mask
that prevents nginx
from accessing it.
const e = require('express')()
e.listen('/sockets/testSocket', (e) => console.error(e))
getfacl /sockets/testSocket
# file: /sockets/testSocket
# owner: nodejs
# group: nodejs
user: :rwx
user:nginx:rw- #effective:r--
group: :r-x
mask: :r-x
other: :r-x
If I create an ordinary file with Nodejs in /sockets
(e.g. by fs.writeFile
) it is created with the same permissions as when I ran touch /sockets/testFile
above, so I don't think it's a problem of Node's umask
.
Likewise, if I run equivalent code to bind to a socket in python
, the results are the same, so I don't think it's a problem with Node itself.
Obviously, this is stopping Nginx from talking to my Express app. Can anyone work out why? :/ The server is running CentOS 7.
The answer is that socket() is a libc function that doesn't implement the ACL policies that are documented at 100%.
Through experimentation I found that you have to set the umask for the calling process, which according to ACL rules should not matter when creating files, and to successfully create sockets the way you want to, you have to: