mirror of
https://github.com/jtesta/ssh-audit.git
synced 2024-12-22 22:15:22 +01:00
Now prints a more user-friendly error message when installed as a Snap package and permission errors are encountered. Updated the Snap build process as well.
This commit is contained in:
parent
22a9559a82
commit
4ace52a190
@ -1,6 +0,0 @@
|
|||||||
all:
|
|
||||||
echo -e "\n\nDid you remember to bump the version number in snapcraft.yaml?\n\n"
|
|
||||||
snapcraft --use-lxd
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf parts/ prime/ snap/ stage/ build/ dist/ src/*.egg-info/ ssh-audit*.snap
|
|
19
PACKAGING.md
19
PACKAGING.md
@ -51,27 +51,14 @@ To download from production server and verify:
|
|||||||
$ pip3 install ssh-audit
|
$ pip3 install ssh-audit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# Snap
|
# Snap
|
||||||
|
|
||||||
To create the snap package, run a fully-updated Ubuntu Server 20.04 VM.
|
To create the snap package, run a fully-updated Ubuntu Server 20.04 VM.
|
||||||
|
|
||||||
Install pre-requisites with:
|
Create the snap package with:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ sudo apt install make snapcraft
|
$ ./build_snap.sh
|
||||||
$ sudo snap install review-tools lxd
|
|
||||||
```
|
|
||||||
|
|
||||||
Initialize LXD:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ sudo lxd init --auto
|
|
||||||
```
|
|
||||||
|
|
||||||
Bump the version number in snapcraft.yaml. Then run:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ make -f Makefile.snap
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Upload the snap with:
|
Upload the snap with:
|
||||||
|
72
build_snap.sh
Executable file
72
build_snap.sh
Executable file
@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# The MIT License (MIT)
|
||||||
|
#
|
||||||
|
# Copyright (C) 2021 Joe Testa (jtesta@positronsecurity.com)
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# build_snap.sh
|
||||||
|
#
|
||||||
|
# Builds a Snap package.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
# Pre-requisites
|
||||||
|
sudo apt install -y make snapcraft
|
||||||
|
sudo snap install review-tools lxd 2> /dev/null
|
||||||
|
|
||||||
|
# Initialize LXD.
|
||||||
|
sudo lxd init --auto
|
||||||
|
|
||||||
|
# Reset the filesystem from any previous runs.
|
||||||
|
rm -rf parts/ prime/ snap/ stage/ build/ dist/ src/*.egg-info/ ssh-audit*.snap
|
||||||
|
git checkout snapcraft.yaml 2> /dev/null
|
||||||
|
git checkout src/ssh_audit/globals.py 2> /dev/null
|
||||||
|
|
||||||
|
# Get the version from the globals.py file.
|
||||||
|
version=$(grep VERSION src/ssh_audit/globals.py | awk 'BEGIN {FS="="} ; {print $2}' | tr -d '[:space:]')
|
||||||
|
|
||||||
|
# Strip the quotes around the version (along with the initial 'v' character) and append "-1" to make the default Snap version (i.e.: 'v2.5.0' => '2.5.0-1')
|
||||||
|
default_snap_version="${version:2:-1}-1"
|
||||||
|
echo -e -n "\nEnter Snap package version [default: ${default_snap_version}]: "
|
||||||
|
read -r snap_version
|
||||||
|
|
||||||
|
# If no version was specified, use the default version.
|
||||||
|
if [[ $snap_version == '' ]]; then
|
||||||
|
snap_version=$default_snap_version
|
||||||
|
echo -e "Using default snap version: ${snap_version}\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure that the snap version fits the format of X.X.X-X.
|
||||||
|
if [[ ! $snap_version =~ ^[0-9]\.[0-9]\.[0-9]\-[0-9]$ ]]; then
|
||||||
|
echo "Error: version string does not match format X.X.X-X!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Append the version field to the end of the file. Not pretty, but it works.
|
||||||
|
echo -e "\nversion: '${snap_version}'" >> snapcraft.yaml
|
||||||
|
|
||||||
|
# Set the SNAP_PACKAGE variable to True so that file permission errors give more user-friendly
|
||||||
|
sed -i 's/SNAP_PACKAGE = False/SNAP_PACKAGE = True/' src/ssh_audit/globals.py
|
||||||
|
|
||||||
|
snapcraft --use-lxd && echo -e "\nDone.\n"
|
@ -1,5 +1,5 @@
|
|||||||
name: ssh-audit
|
name: ssh-audit
|
||||||
version: '2.5.0-1'
|
# 'version' field will be automatically added by build_snap.sh.
|
||||||
license: 'MIT'
|
license: 'MIT'
|
||||||
summary: ssh-audit
|
summary: ssh-audit
|
||||||
description: |
|
description: |
|
||||||
@ -12,10 +12,9 @@ confinement: strict
|
|||||||
apps:
|
apps:
|
||||||
ssh-audit:
|
ssh-audit:
|
||||||
command: bin/ssh-audit
|
command: bin/ssh-audit
|
||||||
plugs: [network,network-bind]
|
plugs: [network,network-bind,home]
|
||||||
|
|
||||||
parts:
|
parts:
|
||||||
ssh-audit:
|
ssh-audit:
|
||||||
plugin: python
|
plugin: python
|
||||||
# python-version: python3
|
|
||||||
source: .
|
source: .
|
||||||
|
@ -21,7 +21,20 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
"""
|
"""
|
||||||
VERSION = 'v2.6.0-dev'
|
# The version to display.
|
||||||
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2' # SSH software to impersonate
|
VERSION = 'v2.6.0'
|
||||||
GITHUB_ISSUES_URL = 'https://github.com/jtesta/ssh-audit/issues' # The URL to the Github issues tracker.
|
|
||||||
|
# SSH software to impersonate
|
||||||
|
SSH_HEADER = 'SSH-{0}-OpenSSH_8.2'
|
||||||
|
|
||||||
|
# The URL to the Github issues tracker.
|
||||||
|
GITHUB_ISSUES_URL = 'https://github.com/jtesta/ssh-audit/issues'
|
||||||
|
|
||||||
|
# The man page. Only filled in on Windows systems.
|
||||||
WINDOWS_MAN_PAGE = ''
|
WINDOWS_MAN_PAGE = ''
|
||||||
|
|
||||||
|
# True when installed from a Snap package, otherwise False.
|
||||||
|
SNAP_PACKAGE = False
|
||||||
|
|
||||||
|
# Error message when installed as a Snap package and a file access fails.
|
||||||
|
SNAP_PERMISSIONS_ERROR = 'Error while accessing file. It appears that ssh-audit was installed as a Snap package. In that case, there are two options: 1.) only try to read & write files in the $HOME/snap/ssh-audit/common/ directory, or 2.) grant permissions to read & write files in $HOME using the following command: "sudo snap connect ssh-audit:home :home"'
|
||||||
|
@ -30,6 +30,7 @@ from datetime import date
|
|||||||
from ssh_audit import exitcodes
|
from ssh_audit import exitcodes
|
||||||
from ssh_audit.ssh2_kex import SSH2_Kex # pylint: disable=unused-import
|
from ssh_audit.ssh2_kex import SSH2_Kex # pylint: disable=unused-import
|
||||||
from ssh_audit.banner import Banner # pylint: disable=unused-import
|
from ssh_audit.banner import Banner # pylint: disable=unused-import
|
||||||
|
from ssh_audit.globals import SNAP_PACKAGE, SNAP_PERMISSIONS_ERROR
|
||||||
|
|
||||||
|
|
||||||
# Validates policy files and performs policy testing
|
# Validates policy files and performs policy testing
|
||||||
@ -122,6 +123,13 @@ class Policy:
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("Error: policy file not found: %s" % policy_file)
|
print("Error: policy file not found: %s" % policy_file)
|
||||||
sys.exit(exitcodes.UNKNOWN_ERROR)
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
except PermissionError as e:
|
||||||
|
# If installed as a Snap package, print a more useful message with potential work-arounds.
|
||||||
|
if SNAP_PACKAGE:
|
||||||
|
print(SNAP_PERMISSIONS_ERROR)
|
||||||
|
else:
|
||||||
|
print("Error: insufficient permissions: %s" % str(e))
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
if policy_data is not None:
|
if policy_data is not None:
|
||||||
|
@ -36,6 +36,8 @@ import traceback
|
|||||||
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
from typing import Dict, List, Set, Sequence, Tuple, Iterable # noqa: F401
|
||||||
from typing import Callable, Optional, Union, Any # noqa: F401
|
from typing import Callable, Optional, Union, Any # noqa: F401
|
||||||
|
|
||||||
|
from ssh_audit.globals import SNAP_PACKAGE
|
||||||
|
from ssh_audit.globals import SNAP_PERMISSIONS_ERROR
|
||||||
from ssh_audit.globals import VERSION
|
from ssh_audit.globals import VERSION
|
||||||
from ssh_audit.globals import WINDOWS_MAN_PAGE
|
from ssh_audit.globals import WINDOWS_MAN_PAGE
|
||||||
from ssh_audit.algorithm import Algorithm
|
from ssh_audit.algorithm import Algorithm
|
||||||
@ -560,18 +562,27 @@ def make_policy(aconf: AuditConf, banner: Optional['Banner'], kex: Optional['SSH
|
|||||||
if aconf.policy_file is None:
|
if aconf.policy_file is None:
|
||||||
raise RuntimeError('Internal error: cannot write policy file since filename is None!')
|
raise RuntimeError('Internal error: cannot write policy file since filename is None!')
|
||||||
|
|
||||||
# Open with mode 'x' (creates the file, or fails if it already exist).
|
succeeded = False
|
||||||
succeeded = True
|
err = ''
|
||||||
try:
|
try:
|
||||||
|
# Open with mode 'x' (creates the file, or fails if it already exist).
|
||||||
with open(aconf.policy_file, 'x', encoding='utf-8') as f:
|
with open(aconf.policy_file, 'x', encoding='utf-8') as f:
|
||||||
f.write(policy_data)
|
f.write(policy_data)
|
||||||
|
succeeded = True
|
||||||
except FileExistsError:
|
except FileExistsError:
|
||||||
succeeded = False
|
err = "Error: file already exists: %s" % aconf.policy_file
|
||||||
|
except PermissionError as e:
|
||||||
|
# If installed as a Snap package, print a more useful message with potential work-arounds.
|
||||||
|
if SNAP_PACKAGE:
|
||||||
|
print(SNAP_PERMISSIONS_ERROR)
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
else:
|
||||||
|
err = "Error: insufficient permissions: %s" % str(e)
|
||||||
|
|
||||||
if succeeded:
|
if succeeded:
|
||||||
print("Wrote policy to %s. Customize as necessary, then run a policy scan with -P option." % aconf.policy_file)
|
print("Wrote policy to %s. Customize as necessary, then run a policy scan with -P option." % aconf.policy_file)
|
||||||
else:
|
else:
|
||||||
print("Error: file already exists: %s" % aconf.policy_file)
|
print(err)
|
||||||
|
|
||||||
|
|
||||||
def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf': # pylint: disable=too-many-statements
|
def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[..., None]) -> 'AuditConf': # pylint: disable=too-many-statements
|
||||||
@ -681,8 +692,16 @@ def process_commandline(out: OutputBuffer, args: List[str], usage_cb: Callable[.
|
|||||||
|
|
||||||
# If a file containing a list of targets was given, read it.
|
# If a file containing a list of targets was given, read it.
|
||||||
if aconf.target_file is not None:
|
if aconf.target_file is not None:
|
||||||
|
try:
|
||||||
with open(aconf.target_file, 'r', encoding='utf-8') as f:
|
with open(aconf.target_file, 'r', encoding='utf-8') as f:
|
||||||
aconf.target_list = f.readlines()
|
aconf.target_list = f.readlines()
|
||||||
|
except PermissionError as e:
|
||||||
|
# If installed as a Snap package, print a more useful message with potential work-arounds.
|
||||||
|
if SNAP_PACKAGE:
|
||||||
|
print(SNAP_PERMISSIONS_ERROR)
|
||||||
|
else:
|
||||||
|
print("Error: insufficient permissions: %s" % str(e))
|
||||||
|
sys.exit(exitcodes.UNKNOWN_ERROR)
|
||||||
|
|
||||||
# Strip out whitespace from each line in target file, and skip empty lines.
|
# Strip out whitespace from each line in target file, and skip empty lines.
|
||||||
aconf.target_list = [target.strip() for target in aconf.target_list if target not in ("", "\n")]
|
aconf.target_list = [target.strip() for target in aconf.target_list if target not in ("", "\n")]
|
||||||
|
Loading…
Reference in New Issue
Block a user