Initial commit
This commit is contained in:
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Hardening security
|
||||||
|
|
||||||
|
https://hackviser.com/tactics/hardening/smb
|
||||||
|
https://hackviser.com/tactics/hardening/caddy
|
||||||
|
https://hackviser.com/tactics/hardening/ssh
|
||||||
|
https://hackviser.com/tactics/hardening/smtp
|
||||||
|
https://hackviser.com/tactics/hardening/rdp
|
||||||
|
|
||||||
|
https://hackviser.com/tactics/pentesting
|
||||||
|
|
||||||
|
https://hackviser.com/tactics/pentesting/services/ssh
|
||||||
5
SETUP-WORKSTATION.md
Normal file
5
SETUP-WORKSTATION.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Chronyd blocks at startup
|
||||||
|
|
||||||
|
chronyd takes care of keeping the system clock in sync. When the system boots, chronyd will block start-up until it has resolved the time. This is useful on systems without a hardware clock (to avoid the system booting as 1970-01-01), but annoying for this setup.
|
||||||
|
|
||||||
|
This behaviour can be disabled by editing /etc/conf.d/chronyd and setting FAST_STARTUP=yes.
|
||||||
38
SETUP.md
Normal file
38
SETUP.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Installation on hardware (Raspberry PI)
|
||||||
|
Raspberry Pi imager (.img)
|
||||||
|
|
||||||
|
> If no internet connection: setup-interfaces with DHCP, rc-service networking restart
|
||||||
|
|
||||||
|
```sh
|
||||||
|
setup-alpine
|
||||||
|
us
|
||||||
|
us
|
||||||
|
|
||||||
|
hostname: alpi
|
||||||
|
ip: 192.168.2.22/24
|
||||||
|
gateway: router (192.168.2.254)
|
||||||
|
netmask 255.255.255.0
|
||||||
|
|
||||||
|
Europe/Amsterdam
|
||||||
|
chrony
|
||||||
|
1
|
||||||
|
YOURUSERNAME
|
||||||
|
YOURNAME
|
||||||
|
github.com/YOURUSERNAME.keys
|
||||||
|
|
||||||
|
openssh
|
||||||
|
y
|
||||||
|
mmcblk0
|
||||||
|
sys
|
||||||
|
y
|
||||||
|
reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
FIRST. Make sure your public key is configured for SSH! Else, next step will LOCK YOU OUT SSH!
|
||||||
|
|
||||||
|
Then, run install.sh by getting it from the internet (wget is in busybox):
|
||||||
|
```sh
|
||||||
|
wget https://TODO
|
||||||
|
chmod +x install.sh
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
22
install.sh
Executable file
22
install.sh
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# echo "Installing Git & cloning installation scripts"
|
||||||
|
apk add git
|
||||||
|
# git clone TODO
|
||||||
|
|
||||||
|
# Install podman-openrc tool
|
||||||
|
apk add cargo
|
||||||
|
cargo install podman-openrc
|
||||||
|
|
||||||
|
base_dir=$(pwd)
|
||||||
|
|
||||||
|
# Run installation scripts
|
||||||
|
cd ./installation
|
||||||
|
source ./basic.sh
|
||||||
|
source ./podman.sh
|
||||||
|
source ./firewall.sh
|
||||||
|
|
||||||
|
cd "$base_dir"
|
||||||
|
|
||||||
|
# Run update script
|
||||||
|
source ./update.sh
|
||||||
17
installation/basic.sh
Normal file
17
installation/basic.sh
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
echo "Basic setup"
|
||||||
|
|
||||||
|
# Enable community repo
|
||||||
|
sed -i 's|^#\(http.*/community\)$|\1|' /etc/apk/repositories
|
||||||
|
apk update
|
||||||
|
|
||||||
|
# Cron jobs
|
||||||
|
rc-update add crond
|
||||||
|
cat << EOF > /etc/periodic/daily/chrony
|
||||||
|
#!/bin/sh
|
||||||
|
chronyc makestep
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Allow local.d services
|
||||||
|
rc-update add local default
|
||||||
|
rc-service local start
|
||||||
14
installation/firewall.sh
Normal file
14
installation/firewall.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
echo "Setting up firewall..."
|
||||||
|
|
||||||
|
apk add -u awall # important -u flag!
|
||||||
|
apk add ip6tables iptables
|
||||||
|
modprobe -v ip_tables
|
||||||
|
modprobe -v ip6_tables
|
||||||
|
modprobe -v iptable_nat #if NAT is used
|
||||||
|
|
||||||
|
# Register services
|
||||||
|
rc-update add iptables
|
||||||
|
rc-update add ip6tables
|
||||||
|
rc-service iptables start
|
||||||
|
rc-service ip6tables start
|
||||||
28
installation/podman.sh
Normal file
28
installation/podman.sh
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
echo "Installing Podman..."
|
||||||
|
|
||||||
|
apk add podman iptables podman-compose
|
||||||
|
rc-update add cgroups
|
||||||
|
rc-service cgroups start
|
||||||
|
|
||||||
|
# Rootless mode
|
||||||
|
adduser -D podman
|
||||||
|
modprobe tun
|
||||||
|
echo tun >> /etc/modules
|
||||||
|
echo podman:100000:65536 > /etc/subuid
|
||||||
|
echo podman:100000:65536 > /etc/subgid
|
||||||
|
doas su -c "podman system migrate" podman
|
||||||
|
|
||||||
|
# Get rid of podman compose docker warning
|
||||||
|
touch /etc/containers/nodocker
|
||||||
|
|
||||||
|
# Fix shared mount with local service
|
||||||
|
cat << EOF > /etc/local.d/mount-rshared.start
|
||||||
|
#!/bin/sh
|
||||||
|
mount --make-rshared /
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x /etc/local.d/mount-rshared.start
|
||||||
|
|
||||||
|
# Allow ports >= 53 to be rootless bound
|
||||||
|
sysctl net.ipv4.ip_unprivileged_port_start=53
|
||||||
11
services/basic/global.policy.json
Normal file
11
services/basic/global.policy.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"description": "Restrict all internet access",
|
||||||
|
"variable": { "internet_if": "eth0" },
|
||||||
|
"zone": {
|
||||||
|
"internet": { "iface": "$internet_if" }
|
||||||
|
},
|
||||||
|
"policy": [
|
||||||
|
{ "in": "internet", "action": "drop" },
|
||||||
|
{ "action": "reject" }
|
||||||
|
]
|
||||||
|
}
|
||||||
11
services/basic/icmp.policy.json
Normal file
11
services/basic/icmp.policy.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"description": "Allow ping-pong",
|
||||||
|
"filter": [
|
||||||
|
{
|
||||||
|
"in": "internet",
|
||||||
|
"service": "ping",
|
||||||
|
"action": "accept",
|
||||||
|
"flow-limit": { "count": 10, "interval": 6 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
11
services/basic/outgoing.policy.json
Normal file
11
services/basic/outgoing.policy.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"description": "Allow outgoing connections for http/https, dns, ssh, ntp, ssh and ping",
|
||||||
|
"filter": [
|
||||||
|
{
|
||||||
|
"in": "_fw",
|
||||||
|
"out": "internet",
|
||||||
|
"service": ["http", "https", "dns", "ssh", "ntp", "ping"],
|
||||||
|
"action": "accept"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
62
services/caddy/config/Caddyfile
Normal file
62
services/caddy/config/Caddyfile
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# https://hackviser.com/tactics/hardening/caddy
|
||||||
|
{
|
||||||
|
auto_https disable_redirects
|
||||||
|
|
||||||
|
# Do not write access logs to journald.
|
||||||
|
log {
|
||||||
|
exclude http.log.access
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write access logs to the logs volume in json
|
||||||
|
# format. Only keep logs for the last 30 days.
|
||||||
|
log access {
|
||||||
|
format json
|
||||||
|
output file /data/logs/access.log {
|
||||||
|
roll_keep_for 720h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block with default http config that accepts requests on
|
||||||
|
# fd/3 and redirects to https.
|
||||||
|
(https-redir) {
|
||||||
|
bind fd/3 {
|
||||||
|
protocols h1
|
||||||
|
}
|
||||||
|
redir https://{host}{uri} 308
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block with default https config that accepts requests on
|
||||||
|
# fd/4 and fdgram/5.
|
||||||
|
(https) {
|
||||||
|
bind fd/4 {
|
||||||
|
protocols h1 h2
|
||||||
|
}
|
||||||
|
bind fdgram/5 {
|
||||||
|
protocols h3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block with compression configuration.
|
||||||
|
(compression) {
|
||||||
|
encode zstd gzip
|
||||||
|
}
|
||||||
|
|
||||||
|
# Block with headers that should be used by most
|
||||||
|
# sites. Add HSTS and some other security headers.
|
||||||
|
# Remove the server header because without it caddy
|
||||||
|
# leaks the backend server version.
|
||||||
|
# https://scotthelme.co.uk/a-new-security-header-referrer-policy/
|
||||||
|
# https://scotthelme.co.uk/content-security-policy-an-introduction/
|
||||||
|
(default-headers) {
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security max-age=31536000; includeSubDomains; preload
|
||||||
|
X-Content-Type-Options nosniff
|
||||||
|
X-Frame-Options sameorigin
|
||||||
|
Content-Security-Policy default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline';
|
||||||
|
Referrer-Policy: same-origin
|
||||||
|
-Server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import *.caddy
|
||||||
11
services/caddy/http.policy.json
Normal file
11
services/caddy/http.policy.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"description": "Allow incoming http (TCP 80 & 443) ports",
|
||||||
|
"filter": [
|
||||||
|
{
|
||||||
|
"in": "internet",
|
||||||
|
"out": "_fw",
|
||||||
|
"service": ["http", "https"],
|
||||||
|
"action": "accept"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
33
services/caddy/service.toml
Normal file
33
services/caddy/service.toml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
user = "podman"
|
||||||
|
capabilities = ["NET_BIND_SERVICE"]
|
||||||
|
|
||||||
|
[service]
|
||||||
|
name = "caddy"
|
||||||
|
image = "caddy:alpine"
|
||||||
|
|
||||||
|
[[mounts]]
|
||||||
|
typ = "bind"
|
||||||
|
source = "$HOME/caddy"
|
||||||
|
target = "/etc/caddy"
|
||||||
|
read_only = true
|
||||||
|
|
||||||
|
[[volumes]]
|
||||||
|
source = "caddy-logs"
|
||||||
|
target = "/data/logs"
|
||||||
|
create = true
|
||||||
|
|
||||||
|
[[volumes]]
|
||||||
|
source = "caddy-data"
|
||||||
|
target = "/data/caddy"
|
||||||
|
create = true
|
||||||
|
|
||||||
|
[[ports]]
|
||||||
|
host = 80
|
||||||
|
container = 80
|
||||||
|
|
||||||
|
[[ports]]
|
||||||
|
host = 443
|
||||||
|
container = 443
|
||||||
|
|
||||||
|
[[networks]]
|
||||||
|
group = "caddy"
|
||||||
8
services/caddy/update.sh
Normal file
8
services/caddy/update.sh
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Symlink config files in base dir
|
||||||
|
find "$base_dir" -name "*.caddy" -exec ln -sf {} "./config" \;
|
||||||
|
|
||||||
|
# Symlink config dir
|
||||||
|
mkdir -p /home/podman/caddy
|
||||||
|
ln -sf ./config /home/podman/caddy
|
||||||
1
services/ssh/ssh.caddy
Normal file
1
services/ssh/ssh.caddy
Normal file
@@ -0,0 +1 @@
|
|||||||
|
test
|
||||||
12
services/ssh/ssh.policy.json
Normal file
12
services/ssh/ssh.policy.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"description": "Allow limited incoming SSH access (TCP/22)",
|
||||||
|
"filter": [
|
||||||
|
{
|
||||||
|
"in": "internet",
|
||||||
|
"out": "_fw",
|
||||||
|
"service": "ssh",
|
||||||
|
"action": "accept",
|
||||||
|
"conn-limit": { "count": 3, "interval": 30 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
25
services/ssh/sshd_config
Normal file
25
services/ssh/sshd_config
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# SSHD config. See https://man.openbsd.org/sshd_config
|
||||||
|
# https://hackviser.com/tactics/hardening/ssh
|
||||||
|
|
||||||
|
# Protocol 2 is more secure
|
||||||
|
Protocol 2
|
||||||
|
|
||||||
|
# No root login or passwords
|
||||||
|
PermitRootLogin no
|
||||||
|
PasswordAuthentication no
|
||||||
|
AuthenticationMethods publickey
|
||||||
|
|
||||||
|
# Allow tunneling, but not with option R (remote)
|
||||||
|
AllowTcpForwarding local
|
||||||
|
GatewayPorts yes
|
||||||
|
|
||||||
|
# override default of no subsystems
|
||||||
|
Subsystem sftp internal-sftp
|
||||||
|
|
||||||
|
# Only allow users that are listed
|
||||||
|
AllowUsers admin
|
||||||
|
|
||||||
|
# Only allow secure ciphers
|
||||||
|
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,mlkem768x25519-sha256
|
||||||
|
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
|
||||||
|
MACs hmac-sha2-256,hmac-sha2-512
|
||||||
2
services/ssh/update.sh
Normal file
2
services/ssh/update.sh
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
ln -sf ./sshd_config /etc/ssh/sshd_config
|
||||||
38
setup-alpine.answerfile
Normal file
38
setup-alpine.answerfile
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# See: https://wiki.alpinelinux.org/wiki/Using_an_answerfile_with_setup-alpine
|
||||||
|
|
||||||
|
# Keymap
|
||||||
|
KEYMAPOPTS="us us"
|
||||||
|
|
||||||
|
# Host name
|
||||||
|
HOSTNAMEOPTS="-n alpi"
|
||||||
|
DNSOPTS=none
|
||||||
|
|
||||||
|
# Contents of /etc/network/interfaces
|
||||||
|
INTERFACESOPTS="auto lo
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
auto eth0
|
||||||
|
iface eth0 inet static
|
||||||
|
address 192.168.2.22
|
||||||
|
netmask 255.255.255.0
|
||||||
|
gateway 192.168.2.254
|
||||||
|
"
|
||||||
|
|
||||||
|
TIMEZONEOPTS="-z Europe/Amsterdam"
|
||||||
|
|
||||||
|
PROXYOPTS=none
|
||||||
|
|
||||||
|
# User
|
||||||
|
USEROPTS="-a -u -g audio,input,video,netdev admin"
|
||||||
|
USERSSHKEY="https://github.com/maurictg.keys"
|
||||||
|
|
||||||
|
# First repo
|
||||||
|
APKREPOSOPTS="-1"
|
||||||
|
|
||||||
|
SSHDOPTS="-c openssh"
|
||||||
|
NTPOPTS="-c chrony"
|
||||||
|
|
||||||
|
# Data disk
|
||||||
|
DISKOPTS="-m sys /dev/mmcblk0"
|
||||||
|
LBUOPTS=none
|
||||||
|
APKCACHEOPTS=none
|
||||||
29
update.sh
Normal file
29
update.sh
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
base_dir=$(pwd)
|
||||||
|
|
||||||
|
echo "Updating service scripts..."
|
||||||
|
podman-openrc ./services /etc/init.d/
|
||||||
|
|
||||||
|
# Update services (awall policies, scripts)
|
||||||
|
for service in "./services"/*/; do
|
||||||
|
[ -d "$service" ] || continue
|
||||||
|
cd "$service" || continue
|
||||||
|
|
||||||
|
# Run update.sh if present
|
||||||
|
if [ -f "update.sh" ]; then
|
||||||
|
source ./update.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Symlink and activate each *.policy.json
|
||||||
|
for policy in *.policy.json; do
|
||||||
|
[ -e "$policy" ] || continue
|
||||||
|
POLICY_NAME="${policy%.policy.json}"
|
||||||
|
ln -sf "./$policy" "/etc/awall/optional/$POLICY_NAME.policy.json"
|
||||||
|
awall enable "$POLICY_NAME.policy"
|
||||||
|
done
|
||||||
|
|
||||||
|
cd "$base_dir"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Activating firewall..."
|
||||||
|
awall activate
|
||||||
Reference in New Issue
Block a user