3 minutes, 36 seconds
A friend of mine created some fun stickers for use at the most recent DEF CON. They were sly commentary about how corporate a lot of the stickers are and how maybe we should get back to our DIY roots. But…what’s this? There’s a .xyz
in there…is that a TLD…is there domain I could go to?! IS THIS STICKER AN AD ITSELF?!?!?!?!1!
(Sticker image is marked with CC0 1.0)
It’s all of those things and none of those things – that’s why I love it so much. Best of all, when you go to website, you get just what you deserve ;)
The website was initially setup on a free hosting provider, but they didn’t provide any logs – something my friend was curious about to see how much traffic the non-ad ad was generating. I have a VERY cheap VPS server that already had Ubuntu server and Caddy on it, and I figured I could help by hosting a wee single file static web site and be able to easily offer the logs. Let’s see what we can do!
Step 1: One HTML file + Four Caddy config lines = Web server
I frickin’ love Caddy! I made a single index.html
file and then added these 4 lines of config:
the-domain-goes-here.xyz {
root * /var/www/the-domain-goes-here.xyz
file_server
}
After I restarted Caddy (systemctl restart caddy
) – I was all set! As DNS had already been changed to point to the IP of my lil’ server, Caddy auto-provisioned a free Let’s Encrypt cert, redirected all traffic from port 80
-> 443
and the site worked perfectly!
By default Caddy has logs turned off – let’s fix that!
Step 2: Turn up the (log) volume
Unsurprisingly, Caddy makes enabling logs very straight forward. Just add these three lines
log {
output file /var/log/caddy/the-domain-goes-here.xyz-access.log
}
I reloaded the config in Caddy (systemctl reload caddy
) and checked for log activity in /var/log/caddy/
. It was there! Oh…it was there in full repetitive, verbose JSON…OK, cool, I guess that’s a sane default in our new cloud init all JSON/YAML all the time world. However, how about common log format though?
This was the first time Caddy surprised me! While it was easy enough to do (huge props to “keen” on Stack Overflow), it was a bit more convoluted and verbose than I expected. You have to change the log deceleration to be log access-formatted
and then specify both a format
and a transform
. The final full server config looks like this:
the-domain-goes-here.xyz {
root * /var/www/the-domain-goes-here.xyz
file_server
log access-formatted {
output file /var/log/caddy/the-domain-goes-here.xyz-access.log
# OMG - thank you!! https://stackoverflow.com/a/76988109
format transform `{request>remote_ip} - {request>user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}" "host:{request>host}"` {
time_format "02/Jan/2006:15:04:05 -0700"
}
}
}
Now let’s figure how to to add secure access to download those logs.
Step 3: Rsync via Authorized Keys FTW!
A straight forward way to give access to the logs would be to create a new user (adduser username
) and then update the user to be able to read the files created by the Caddy process by adding them to the right group (usermod -a -G caddy username
). This indeed worked well enough, but it also gave the user a full shell account on the web server. While they’re a friend and I trust them, I also wanted see if there was a more secure way of granting access.
From prior projects, I knew you could force an SSH session to immediately execute a command upon login, and only that command, by prepending this to the entry in the authorized_key
file:
command="SOME_COMMAND",no-port-forwarding,no-user-rc SSH-KEY-HERE
If I had SOME_COMMAND
be /usr/bin/rsync
then this would be great! The user could easily sync the updates to their access log file at /var/log/caddy/the-domain-goes-here.xyz-access.log
. but then I realized they could also rsync
off ANY file that they had read access too. That’s not ideal.
The final piece to this Simple Single Page Site with Secure Log Access is rrsync
. This is a python script developed specifically for the use case of allowing users to rsync only specific files via the Authorized Keys trick. The full array of security flags now looks like this:
restrict,command="/usr/bin/rrsync -ro /var/log/caddy/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding SSH-KEY-HERE
As there’s no other logs in /var/log/caddy – this works great! The user just needs to call:
rsync -axv username@the-domain-goes-here.xyz: .
Because of the magic of rrsync
(two r
s) on the server forcing them into a specific remote directory, the rsync
(one r
) on client is none the wiser and happily syncs away.
Happy web serving and secure log access syncing and Happy Halloween!