Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block SSH shell access to git repositories #374

Merged
merged 13 commits into from
Sep 1, 2020
3 changes: 3 additions & 0 deletions scripts/no-interactive-login
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh
printf '%s\n' "Hi! You've successfully authenticated, but myProxy does not provide interactive shell access."
exit 128
2 changes: 1 addition & 1 deletion scripts/post-receive
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ git clean -f
git checkout master
git branch -D prod
npm install
pm2 startOrRestart deploy.config.js --env production --update-env
sudo -u myproxy pm2 startOrRestart deploy.config.js --env production --update-env
19 changes: 19 additions & 0 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,33 @@ if [ ! -d "./acme.sh" ] ; then
cd ../
fi
if [ ! -d "/home/myproxy" ] ; then
# Add users
sudo useradd -m -c "myproxy" myproxy -s /bin/bash -p $(echo $ADMIN | openssl passwd -1 -stdin) -d "/home/myproxy"
sudo useradd -m -G myproxy -s $(which git-shell) -p $(echo $ADMIN | openssl passwd -1 -stdin) git
# Add sudoers rule for git user to run pm2 as myproxy, without password
echo "git ALL = (myproxy) NOPASSWD: /usr/bin/pm2" > /etc/sudoers.d/git
# Create folders
mkdir /home/myproxy/.ssh
mkdir /home/git/.ssh
mkdir /home/myproxy/.scripts
# Copy ssh keys and scripts
cp ~/.ssh/authorized_keys /home/myproxy/.ssh/authorized_keys
cp ~/.ssh/authorized_keys /home/git/.ssh/authorized_keys
cp ./scripts/post-receive /home/myproxy/.scripts/post-receive
cp ./scripts/pre-receive /home/myproxy/.scripts/pre-receive
cp ./scripts/gitignore /home/myproxy/.scripts/.gitignore
# Disable SSH MOTD message for git user
touch /home/git/.hushlogin
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This disables the MOTD sent from the server when someone tries to SSH in. For example:

$ ssh [email protected]
PTY allocation request failed on channel 0
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-42-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Sep  1 13:15:29 UTC 2020

  System load:  0.72               Users logged in:          1
  Usage of /:   18.9% of 24.06GB   IPv4 address for docker0: 172.17.0.1
  Memory usage: 48%                IPv4 address for eth0:    157.245.253.104
  Swap usage:   0%                 IPv4 address for eth0:    10.10.0.5
  Processes:    130

13 updates can be installed immediately.
0 of these updates are security updates.
To see these additional updates run: apt list --upgradable


fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to challenges.ggwadera.xyz closed.

Becomes:

$ ssh [email protected]
PTY allocation request failed on channel 0
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to challenges.ggwadera.xyz closed.

# Add git-shell message
mkdir /home/git/git-shell-commands
cp ./scripts/no-interactive-login /home/git/git-shell-commands/no-interactive-login
chmod +x /home/git/git-shell-commands/no-interactive-login
# fix file permissions
chown myproxy:myproxy -R /home/myproxy/
chown git:git -R /home/git/
chmod 2775 -R /home/myproxy/
# Prepend ssh options for authorized keys
sed -i '/^ssh-rsa/s/^/no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty /' /home/git/.ssh/authorized_keys
fi
npm run build
if [ ! -f "./data.db" ] ; then
Expand Down
17 changes: 13 additions & 4 deletions src/api/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '../lib/data'
import { Mapping } from '../types/general'
import prodConfigure from '../../scripts/prod.config.js'
import { getGitUserId } from '../helpers/getGitUser'
import { getGitUserId, getGitGroupId } from '../helpers/getGitUser'
import environment from '../helpers/environment'
const mappingRouter = express.Router()
const exec = util.promisify(cp.exec)
Expand Down Expand Up @@ -61,7 +61,7 @@ mappingRouter.post('/', async (req, res) => {
port: req.body.port || `${portCounter}`,
ip: req.body.ip || '127.0.0.1',
id: uuid4(),
gitLink: `myproxy@${req.body.domain}:${WORKPATH}/${fullDomain}`,
gitLink: `git@${req.body.domain}:${WORKPATH}/${fullDomain}`,
fullDomain
}
domainKeys.push(mappingObject)
Expand All @@ -72,9 +72,14 @@ mappingRouter.post('/', async (req, res) => {
if (!isProduction()) {
return respond()
}

// get user and group id to execute the commands with the correct permissions
const gitUserId = await getGitUserId()
const gitGroupId = await getGitGroupId()

exec(
`
umask 002
cd ${WORKPATH}
mkdir ${fullDomain}
git init ${fullDomain}
Expand All @@ -88,7 +93,7 @@ mappingRouter.post('/', async (req, res) => {
git add .
git commit -m "Initial Commit"
`,
{ uid: gitUserId }
{ uid: gitUserId, gid: gitGroupId }
)
.then(() => {
respond()
Expand Down Expand Up @@ -126,7 +131,11 @@ mappingRouter.delete('/:id', async (req, res) => {
const deletedDomain = getMappingById(req.params.id)
deleteDomain(deletedDomain.fullDomain)
if (!isProduction()) return res.json(deletedDomain)

// get user and group id to execute the commands with the correct permissions
const gitUserId = await getGitUserId()
const gitGroupId = await getGitGroupId()

exec(
`
cd ${WORKPATH}
Expand All @@ -136,7 +145,7 @@ mappingRouter.delete('/:id', async (req, res) => {
fi
rm -rf ${deletedDomain.fullDomain}
`,
{ uid: gitUserId }
{ uid: gitUserId, gid: gitGroupId }
).then(() => {
res.json(deletedDomain)
})
Expand Down
6 changes: 4 additions & 2 deletions src/helpers/authorizedKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import fs from 'fs'
import environment from '../helpers/environment'

const { isProduction } = environment
const sshOptions =
'no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty'
let authorizedKeys: Array<string> = []

const updateSSHKey = (): void => {
if (isProduction()) {
const file = fs.createWriteStream('/home/myproxy/.ssh/authorized_keys')
const file = fs.createWriteStream('/home/git/.ssh/authorized_keys')
file.on('error', err => {
console.log(err)
})
authorizedKeys.forEach(v => {
file.write(`${v}\n`)
file.write(`${sshOptions} ${v}\n`)
})
file.end()
}
Expand Down
7 changes: 6 additions & 1 deletion src/helpers/getGitUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ const getGitUserId = async (): Promise<number> => {
return parseInt(gitId.stdout, 10)
}

export { getGitUserId }
const getGitGroupId = async (): Promise<number> => {
const gitId = await exec('getent group myproxy | cut -d: -f3')
return parseInt(gitId.stdout, 10)
}

export { getGitUserId, getGitGroupId }