aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--mds/NTP.txt144
-rw-r--r--mds/oneclientforeverything.txt96
-rw-r--r--mds/securedocker.txt611
-rw-r--r--put_in_db.js8
4 files changed, 850 insertions, 9 deletions
diff --git a/mds/NTP.txt b/mds/NTP.txt
index 8060191..ebb7997 100644
--- a/mds/NTP.txt
+++ b/mds/NTP.txt
@@ -1,7 +1,7 @@
-== After NTP Comes NTS
+== After NTP Comes NTS. After NTS comes sdwdate.
Well for this one I will be talking a bit about NTP and NTS. Unlike the
-DNS post there isnt much going on here.
+DNS post there isn’t much going on here.
NTP is plain-text, NTS uses TLS so if our requests are tampered with, we
can know. There is the ``oooh, you cant see what I’m sending now'' but
@@ -19,6 +19,9 @@ tampered with
* REQ-003: It should not be known which time servers are being used
upstream by the client
+If you are wondering why any of this even matters you can have a look
+https://www.whonix.org/wiki/Time_Attacks[here].
+
Now talk about the problem. The protocol is fine. We are sending TCP
with TLS here. That’s brilliant. We get all this:
@@ -34,7 +37,7 @@ with TLS here. That’s brilliant. We get all this:
* Performance: NTS must not significantly degrade the quality of the time transfer. The encryption and authentication used when actually transferring time should be lightweight.
....
-exerpt from https://www.rfc-editor.org/rfc/rfc8915[RFC 8915]
+Excerpt from https://www.rfc-editor.org/rfc/rfc8915[RFC 8915]
If we find a client that lets us use a SOCKS5 proxy, then we can send
our NTS requests over Tor and then call it a day. REQ-002 and REQ-003
@@ -51,7 +54,7 @@ SOCKS5 proxies.
* for ntpd-rs look
https://github.com/pendulum-project/ntpd-rs/discussions/1365[here]
-Which menas our setup is not complete.
+Which means our setup is not complete.
=== Implementation
@@ -106,7 +109,7 @@ listen = "10.167.131.1:123"
listen = "[::1]:123"
----
-[source,config]
+[source,conf]
----
nts enable
nts key /etc/letsencrypt/live/nts.dehein.org/privkey.pem
@@ -169,15 +172,142 @@ volumes:
vault:
----
+=== What comes after NTS
+
+Above we looked at NTP and NTS. We failed to find a client that supports
+SOCKS5 but that’s a trivial matter. What is not trivial, however, is how
+NTS and NTP work, and by that I mean you will still have to ask a server
+to tell you the time. Doing so over Tor or other anonymizing networks
+should be fine but we can choose to try out another method of doing
+things. Enter `sdwdate`
+
+==== sdwdate
+
+It still has the same flaw as NTP/NTS as in we still have to trust a
+server not to lie
+https://www.kicksecure.com/wiki/Sdwdate#sdwdate_Source_Pools[please look
+here]. Personally, It is a bit of a disappointment that the protocol
+that’s supposed to be oh-so-much-shinier and newer than NTP has the same
+flawed mechanism as NTP. Now granted having hardware that tells you the
+time so that you can share that with everyone else is not something
+trivial or readily-available but this only makes sdwdate desirable in
+the absence of an NTS client that support SOCKS5 proxy. Once that is
+done, the larger user pool of NTS/NTP will offer more protection against
+the smaller userbase of sdwdate. sdwdate gives a table of comparison
+between itself and NTP. Let’s take at look at that:
+
+Let’s take a look at `sdwdate`. It is a roller-coaster. And I do mean
+that. So don’t make up your mind until the very end. There is a
+comparison between NTP and sdwdate made
+https://www.kicksecure.com/wiki/Sdwdate#Sdwdate_vs_NTP[here] by
+kicksecure themselves.
+
+[cols=",,",options="header",]
+|===
+|category |sdwdate |ntp
+|written in memory-safe language |Yes |No
+|distributed trust |Yes |No
+|secure connection by default |Yes |No
+|gradual clock adjustments |Yes |Yes
+|daemon |Yes |Yes
+|functional over tor |Yes |No
+|tor not required |No |Yes
+|client, time fetcher |Yes |Yes
+|Server, time provider |No |Yes
+|AppArmor profile |Yes |Yes
+|systemd security hardening,seccomp |Yes |?
+|drop-in config folder |Yes |No
+|proxy support |Yes |No
+|possible to secure by default on GNU/Linux distribution level |Yes |No
+|secure |Yes |No
+|optional GUI |Yes |No
+|===
+
+* memory-safety: I mean its good and all that sdwdate uses a memory-safe
+language(python) but NTP is a protocol. Not sure how NTP is bound to a
+single programming language. The one client we mentioned before uses
+rust which guarantees memory safety.
+* secure connection by default: NTS uses TLS v1.3 . Not sure why sdwdate
+is being compared against NTP and not NTS.
+* functional over Tor: again, NTS uses TCP which can pass through a
+SOCKS5 proxy as is implemented by the current incarnation of Tor. Also,
+not sure, but are we comparing against the NTP protocol or a specific
+implementation?
+* Tor not required: what if I want to use
+https://github.com/PurpleI2P/i2pd[i2p] or
+https://github.com/yggdrasil-network/yggdrasil-go[yggdrasil] to sync
+time over? Why does it have to be Tor?
+* apparmor profile: not sure why this is even included. You can write
+one for NTP implementations.
+* systemd security hardening, seccomp: same as above. You can do it for
+NTP/NTS implementations as well.
+* drop-in config folder: what’s a folder? Is that supposed to be a
+directory? Second, what does that even mean? And third, who is writing
+these? The only kind of people who make this sort of mistake are people
+who use MS Windows more than Linux. This is official kicksecure
+documentation. You have Windows users writing these for the ultra secure
+and hardened ``Linux'', I’ll say it again, ``Linux'', distro?
+* proxy support: again, NTS uses TCP so it supports SOCKS5 proxies as
+well but for whatever reason we are comparing against NTP(though whether
+we are comparing against the protocol or an implementation is something
+left to be decided by the next generation of humans)
+* possible to secure by default on GNU/Linux distribution level: whats
+the GNU/Linux distribution level? What does this even mean? You can
+secure it on the OS level? I mean it’s software so I would hope that it
+would be possible to secure it on the software level.
+* secure: what are the criteria? Secure against what? And again, why are
+we comparing to NTP and not NTS?
+* optional GUI: again not sure why we keep zig-zagging between comparing
+implementations and the protocols. In conclusion, why is that table even
+there? What purpose does it even serve?
+
+If we were going to base our judgement on the documentation provided on
+kicksecure’s website, I am sorry to say that `sdwdate` does a very poor
+job but fortunately that’s not all there is to it.
+
+Now let’s go take a look at the github README for the project:
+
+[source,txt]
+----
+At randomized intervals, sdwdate connects to a variety of webservers and extracts the time stamps from http headers (RFC 2616))
+----
+
+This is our first spark of brilliance. The second spark is when we
+consider the practical meaning of only being able to use Tor v3
+addresses. Like a wise man once said:
+
+[source,txt]
+----
+amateurs practice something until they can get it right. pros practice something until they can't get it wrong.
+----
+
+The result of using only Tor v3 addresses is that you cannot leak your
+real IP address no matter what happens. You either have a working Tor
+proxy in which case the IP address will be that of the exit node or none
+at all.
+
+Now we know we definitely are dealing with a very promising solution.
+`sdwdate' extracts the time stamp in the http header so we are not
+asking a known NTP server about the time, we are just doing a normal
+http request.
+
+=== DISCLAIMER
+
+Although unrelated, it is worth noting that the kicksecure docs are
+pretty good even if you are not planning on using kicksecure.
+
=== Links
* https://www.rfc-editor.org/rfc/rfc8915[RFC 8915]
* https://github.com/jauderho/nts-servers[Here] you can find a list of
publicly available servers that support NTS
+* https://github.com/Kicksecure/sdwdate[sdwdate’s github page]
+* https://www.kicksecure.com/wiki/Sdwdate[sdwdate doc]
+* https://www.rfc-editor.org/rfc/rfc2616[RFC 2616]
-timestamp:1709418680
+timestamp:1713478033
-version:1.0.0
+version:1.1.0
https://blog.terminaldweller.com/rss/feed
diff --git a/mds/oneclientforeverything.txt b/mds/oneclientforeverything.txt
index 9d61a5b..dff38b7 100644
--- a/mds/oneclientforeverything.txt
+++ b/mds/oneclientforeverything.txt
@@ -244,9 +244,101 @@ volumes:
matterircddb:
----
-timestamp:1699398469
+==== SMS
+
+I have an entire post about how one can get their SMS on IRC
+link:posts/how_to_get_your_sms_on_irc[here]. You need a piece of
+software on your phone to forward the SMS to a web hook server and then
+we send the SMS over to IRC. You can find the web-hook server that I use
+https://github.com/terminaldweller/sms-webhook[here].
+
+==== where to sink all the bridges
+
+Bridges connect two things. You need to have a sink for your bridges. I
+was contemplating making a lot of invite-only channels protected by
+password on public networks then I found out about
+https://github.com/ergochat/ergo[ergo]. I’d say the main advantage of
+using ergo is, it’s easy to setup. You don’t need any other services to
+run to get basic functionality like chanserv or nickserv. You don’t even
+need a bouncer if you need to have your messages when your client
+disconnects. ergo has that functionality built-in. Here are some other
+perks:
+
+* ergo allow you to define a ``private'' IRC network. You do that by
+requiring SASL while connecting, so others can’t connect to your
+instance without having an account
+* it is under active development
+* it has good documentation
+* its one executable written in go so it’s very easy to deploy
+
+==== bots
+
+We have LLMs now. The genie is out of the box. They are useful.’ I
+needed a bunch of them to I wrote
+https://github.com/terminaldweller/milla[milla]. At the time of writing
+milla supports chatgpt, gemini and of course ollama.
+
+===== Deploying milla
-version:0.1.0
+[source,yaml]
+----
+version: "3.9"
+services:
+ milla:
+ image: milla
+ build:
+ context: .
+ deploy:
+ resources:
+ limits:
+ memory: 64M
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "100m"
+ networks:
+ - millanet
+ restart: unless-stopped
+ command: ["--config", "/opt/milla/config.toml"]
+ volumes:
+ - ./config.toml:/opt/milla/config.toml
+ cap_drop:
+ - ALL
+ dns:
+ - 9.9.9.9
+ environment:
+ - SERVER_DEPLOYMENT_TYPE=deployment
+ entrypoint: ["/milla/milla"]
+networks:
+ millanet:
+----
+
+[source,toml]
+----
+ircServer = "irc.terminaldweller.com"
+ircPort = 6697
+ircNick = "mybot"
+ircSaslUser = "mybot"
+ircSaslPass = "mypass"
+ircChannel = "#mychannel"
+ollamaEndpoint = ""
+temp = 0.2
+ollamaSystem = ""
+requestTimeout = 10
+millaReconnectDelay = 60
+enableSasl = true
+model = "llama2-uncensored"
+chromaStyle = "rose-pine-moon"
+chromaFormatter = "terminal256"
+provider = "ollama" # ollama, chatgpt, gemini
+apikey = "key"
+topP = 0.9
+topK = 20
+----
+
+timestamp:1713480455
+
+version:1.0.0
https://blog.terminaldweller.com/rss/feed
diff --git a/mds/securedocker.txt b/mds/securedocker.txt
new file mode 100644
index 0000000..62a4796
--- /dev/null
+++ b/mds/securedocker.txt
@@ -0,0 +1,611 @@
+== Docker, Linux, Security. Kinda.
+
+We will be exploring some Linux features in the context of a docker
+application container. Another way of explaining it would be to say we
+will talk about how to make more secure application containers. We will
+not talk about firewall and apparmor because they are tools that enhance
+security on the host in general and not specific to a docker application
+container. A secure host means a more secure application container but
+that is discussion for another post. We will focus on Linux containers
+since FreeBSD containers are still experimental(see
+https://wiki.freebsd.org/Docker[here] and
+https://github.com/samuelkarp/runj[here]). Yes, windows containers
+exist. We will not discuss performance. Here be performance penalties,
+but again that is not the focus of this post.
+
+Before we begin, Linux docker containers are Linux. They are using most
+of the functionality that existed before application containers in the
+form of docker were a thing. Knowing Linux better means you know Linux
+Docker containers(application containers is a more correct term) better.
+We will see this point throughout this post.
+
+=== Base Image
+
+We start with the first building block of a new docker image, The base
+image. By far the most used base images are the Alpine docker base
+image, followed by Debian and Ubuntu docker base images. These distros
+have two major differences that we want to focus on:
+
+* C standard library implementation
+* the userspace utility implementation
+
+Debian and Ubuntu(we are not forgetting that Ubuntu itself is a Debian
+derivative) both use glibc, as in gnu’s
+https://www.gnu.org/software/libc/[libc] implementation. Alpine uses
+https://www.musl-libc.org/[musl-libc] as its C standard library
+implementation. The major difference here which will come into play
+later on again is glibc has been around for much longer, so it has to
+keep backwards compatibility for a much longer period of time and for
+far more many things. Also the general attitude with the glibc team is
+that they have to support everything since if they don’t then who will?
+Libmusl on the other hand, does not try to support everything under the
+sun, a relatively newer project, comparatively, and, they keep their
+codebase lean. As a result not all applications are supported by libmusl
+but a good number of them are. In simpler terms, libmusl has a far
+smaller attack surface compared to glibc.
+
+On to our second point, which is the cli utilities’ implementation.
+Debian and Ubuntu use gnu’s
+https://www.gnu.org/software/coreutils/[Coreutils] while Alpine uses
+https://busybox.net/[Busybox](remember, we are talking about the most
+used application container bases. You can install a desktop version of
+Alpine with GNU coreutils). Here we have the same situation as before,
+The GNU coreutils are bigger, do more and have a larger attack surface.
+Busybox is smaller, does not support as many features as GNU Coreutils
+but does support enough of them to make them useful. Needless to say,
+busybox is small and hence, it has a smaller attack surface.
+
+To get a feel for how this plays out in the real world, you can look at
+some of the popular images that come in both Debian and Alpine flavours
+on dockerhub. Take a look at the number of reported vulnerabilities for
+both bases. The theme we observe is simple. The bigger the attack
+surface the bigger the number of vulnerabilities.
+
+Alpine images are small, lean and functional, just like libmusl and
+busybox but there are still quite a few things on an alpine image that
+are extraneous. We can take them out and have a perfectly functioning
+application container.
+
+That’s how we get
+https://github.com/GoogleContainerTools/distroless[distroless].
+Distroless base images follow the same pattern as alpine base docker
+images, as in, less functionality while still keeping enough
+functionality to be able to do the job and minimize the attack surface.
+Minimizing a base image like this means that the base images are very
+specialized so we have base images for golang, python, java and the
+like.
+
+=== Dokcer Runtimes
+
+By default docker uses containerd which in turn uses runc for the
+runtime. There are two additional runtimes that we want to focus on who
+try to provide a more secure runtime environment for docker.
+
+* gvisor
+* kata
+
+==== gvisor
+
+gVisor creates a sandbox environment. Containers interact with the host
+through this sandboxed environment. gvisor has two components. Gofer and
+Sentry. Sentry is a kernel that runs the containers and intercepts and
+responds to system calls made by the application so as not to have an
+application directly control the syscalls that it makes. Gofer handles
+filesystem access(not /proc) for the application. The application is a
+regular application. gVisor aims to provide an environment equivalent to
+Linux 4.4. gvisor presently does not implement every system call,
+`/proc` file or `/sys` file. Every sandbox environment gets its own
+instance of Sentry. Every container in the sandbox gets its own instance
+of Gofer. gVisor currently does not support all system calls. You can
+find the list of supported system calls for amd64
+https://gvisor.dev/docs/user_guide/compatibility/linux/amd64/[here].
+
+....
+ -------------
+ |Application|
+ -------------
+ |system calls
+ |
+ -------- 9p -------
+ |Sentry|<------->|Gofer|
+ -------- -------
+ | limited |system
+ | syscalls |calls
+ ---------------
+ | Host Kernel |
+ ---------------
+ |
+ |hardware
+....
+
+==== kata
+
+Kata creates a sandbox environment for containers to interact with as
+proxy, not too dissimilar to gvisor but the main point of difference is
+that kata uses a VM to achieve this.
+
+gVisor and katacontainers allow us to implement defense in depth when it
+comes to application containers and host system security.
+
+=== Capabilites and Syscalls
+
+Let’s talk about capabilities for a bit.
+
+From
+https://manpages.debian.org/bookworm/manpages/capabilities.7.en.html[man
+7 capabilities]:
+
+[source,txt]
+----
+For the purpose of performing permission checks, traditional UNIX implementations distinguish two
+categories of processes: privileged processes (whose effective user ID is 0, referred to as
+superuser or root), and unprivileged processes (whose effective UID is nonzero). Privileged
+processes bypass all kernel permission checks, while unprivileged processes are subject to full
+permission checking based on the process's credentials (usually: effective UID, effective GID, and
+supplementary group list).
+
+Starting with Linux 2.2, Linux divides the privileges traditionally associated with superuser into
+distinct units, known as capabilities, which can be independently enabled and disabled.
+Capabilities are a per-thread attribute.
+----
+
+Capabilities give you a more granular control over which privileges to
+give instead of just root and non-root. Docker let’s us choose which
+capabilities to give to a container. So we can for example allow a
+non-privileged process to bind to privileged ports using capabilities.
+As an example, a simple application making calls to API endpoints and
+writing results back to a database does not require any capabilities. It
+can run under a non-privileged user with no capabilities and do all the
+tasks that it needs to do. That being said, determining which
+capabilities are required can be a bit challenging when it comes to
+certain applications since there is no straightforward way of achieving
+this. In certain cases we can get away with dropping all capabilities,
+running our application and then trying to figure out, based on the
+received error messages, which capability is missing and needs to be
+given to the application. But in certain cases this may not be feasible
+or practical.
+
+From
+https://manpages.debian.org/bookworm/manpages-dev/syscalls.2.en.html[man
+2 sycalls]:
+
+[source,txt]
+----
+The system call is the fundamental interface between an application and the Linux kernel.
+----
+
+The Linux kernel lets us choose which ones of these interface calls can
+be allowed to be made by an application. We can essentially filter which
+syscalls are allowed and which ones are not on a per application basis.
+Docker enables this functionality with an arguably more friendly
+approach. Capabilities and syscall filtering are tools to implement
+principle of least privilege. Ideally, we would like to allow a
+container to only have access to what it needs and just that. Not more,
+and obviously not less.
+
+==== capabilities in the wild
+
+Capabilities are a Linux feature, docker allows us to use that with
+application containers. We’ll look at a very simple example of how one
+can set capabilities for a regular executable on Linux.
+https://manpages.debian.org/bookworm/libcap2-bin/setcap.8.en.html[man 8
+setcap] lets us set capabilities for a file.
+
+==== syscall Filtering in the wild
+
+As an example we will look at
+https://manpages.debian.org/bookworm/bubblewrap/bwrap.1.en.html[man 1
+bwrap]. https://github.com/containers/bubblewrap[Bubblewrap] allows us
+to sandbox an application, not too dissimilar to docker. Flatpaks use
+bubblewrap as part of their sandbox. Bubblewrap can optionally take in a
+list of syscalls to
+https://www.kernel.org/doc/html/v4.19/userspace-api/seccomp_filter.html[filter].
+The filter is expressed as a BPF(Berkley Packet Filter program -
+remember when I said docker gives you a
+https://docs.docker.com/engine/security/seccomp/[friendlier] interface
+to seccomp?) program. Below is a short program that defines a BPF
+program that can be passed to an application using bwrap that lets us
+log all the sycalls the application makes to syslog.
+
+[source,c]
+----
+#include <fcntl.h>
+#include <seccomp.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+void log_all_syscalls(void) {
+ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_LOG);
+ seccomp_arch_add(ctx, SCMP_ARCH_X86_64);
+ seccomp_export_bpf(ctx, 1);
+ seccomp_export_pfc(ctx, 2);
+ seccomp_release(ctx);
+}
+
+int main(int argc, char **argv) {
+ log_all_syscalls();
+}
+----
+
+Building is straightforward. Just remember to link against `libseccomp`
+with `-lseccomp`.
+
+[source,bash]
+----
+gcc main.c -lseccomp
+----
+
+Running the above code we get this:
+
+[source,txt]
+----
+ > 5@#
+# pseudo filter code start
+#
+# filter for arch x86_64 (3221225534)
+if ($arch == 3221225534)
+ # default action
+ action LOG;
+# invalid architecture action
+action KILL;
+#
+# pseudo filter code end
+#
+----
+
+[source,bash]
+----
+#!/usr/bin/dash
+
+TEMP_LOG=/tmp/seccomp_logging_filter.bpf
+
+./a.out > ${TEMP_LOG}
+
+bwrap --seccomp 9 9<${TEMP_LOG} bash
+----
+
+Then we can go and see where the logs end up. On my host, they are
+logged under `/var/log/audit/audit.log` and they look like this:
+
+....
+type=SECCOMP msg=audit(1716144132.339:4036728): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=13 compat=0 ip=0x7fa58591298f code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=rt_sigaction
+type=SECCOMP msg=audit(1716144132.339:4036729): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=13 compat=0 ip=0x7fa58591298f code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=rt_sigaction
+type=SECCOMP msg=audit(1716144132.339:4036730): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=13 compat=0 ip=0x7fa58591298f code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=rt_sigaction
+type=SECCOMP msg=audit(1716144132.339:4036731): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=13 compat=0 ip=0x7fa58591298f code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=rt_sigaction
+type=SECCOMP msg=audit(1716144132.339:4036732): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=13 compat=0 ip=0x7fa58591298f code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=rt_sigaction
+type=SECCOMP msg=audit(1716144132.339:4036733): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=14 compat=0 ip=0x7fa5859664f4 code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=rt_sigprocmask
+type=SECCOMP msg=audit(1716144132.339:4036734): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=13 compat=0 ip=0x7fa58591298f code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=rt_sigaction
+type=SECCOMP msg=audit(1716144132.339:4036735): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=1 compat=0 ip=0x7fa5859ce5d0 code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=write
+type=SECCOMP msg=audit(1716144132.339:4036736): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=1 compat=0 ip=0x7fa5859ce5d0 code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=write
+type=SECCOMP msg=audit(1716144132.339:4036737): auid=1000 uid=1000 gid=1000 ses=1 subj=unconfined pid=19633 comm="bash" exe="/usr/bin/bash" sig=0 arch=c000003e syscall=270 compat=0 ip=0x7fa5859d77bc code=0x7ffc0000AUID="devi" UID="devi" GID="devi" ARCH=x86_64 SYSCALL=pselect6
+....
+
+Docker allows us to do the
+https://docs.docker.com/engine/security/seccomp/[same]. We can give
+docker a seccomp profile to filter out the syscalls that are not
+required for a specific container. You can find the default docker
+seccomp profile
+https://github.com/moby/moby/blob/master/profiles/seccomp/default.json[here].
+
+=== Namespaces
+
+....
+A namespace wraps a global system resource in an abstraction that makes it appear to the processes
+within the namespace that they have their own isolated instance of the global resource. Changes
+to the global resource are visible to other processes that are members of the namespace, but are
+invisible to other processes. One use of namespaces is to implement containers.
+....
+
+From
+https://manpages.debian.org/bookworm/manpages/namespaces.7.en.html[man 7
+namespaces]. You can think of namespaces as almost the same thing as a
+namespace does in some programming languages. Docker uses its own
+namespaces for the containers so as to further isolate the application
+containers from the host system.
+
+==== Namespaces in the Wild
+
+As an example let’s look at the script provided below. Here we are
+creating a new network namespace. The new interface is provided by
+simply connecting an android phone for USB tethering. Depending on the
+situation you have going on and the `udev` naming rules the interface
+name will differ but the concept is the same. We are creating a new
+network namespace for a second internet provider, which in this case, is
+our android phone. We then use this network namespace to execute
+commands in the context of this specific network namespace. Essentially,
+we can choose which applications get to use our phone internet and which
+ones use whatever it is we were previously connected to.
+
+[source,sh]
+----
+#!/usr/bin/env sh
+PHONE_NS=phone_ns
+IF=enp0s20f0u6
+
+sudo ip netns add ${PHONE_NS}
+sudo ip link set ${IF} netns ${PHONE_NS}
+sudo ip netns exec ${PHONE_NS} ip link set ${IF} up
+sudo ip netns exec ${PHONE_NS} ip link set dev lo up
+sudo ip netns exec ${PHONE_NS} dhclient ${IF}
+----
+
+[source,sh]
+----
+$ sudo ip netns exec home_ns curl -4 icanhaveip.com
+113.158.237.102
+$ curl -4 icanhasip.com
+114.201.132.98
+----
+
+*_HINT_*: The IP addresses are made up. The only thing that matters is
+that they are different.
+
+Since we have the android phone’s interface on another namespace the two
+cannot interfere with each other. This is pretty much how docker uses
+namespaces. Without a network namespace we would have to make a small
+VM, run a VPN on the VM and then make a socks5 proxy to the VM from the
+host and then have applications pass their traffic through a socks5
+proxy with varying degrees of success. *_NOTE_*: since we are not
+running the script on a hook, you might blow out your net having two
+upstreams at the same time. In which case, run the script, then restart
+NetworkManager or whatever you have.
+
+=== SBOM and Provenance Attestation
+
+What is SBOM? NIST defines SBOM as a ``formal record containing the
+details and supply chain relationships of various components used in
+building software.''. It contains details about the components used to
+create a certain piece of software. SBOM is meant to help mitigate the
+threat of supply chain attacks(remember xz?).
+
+What is provenance?
+
+....
+The provenance attestations include facts about the build process, including details such as:
+
+ Build timestamps
+ Build parameters and environment
+ Version control metadata
+ Source code details
+ Materials (files, scripts) consumed during the build
+....
+
+https://docs.docker.com/build/attestations/sbom/[source]
+
+==== Example
+
+Let’s review all that we learned about in the form of a light exercise.
+
+For the first build, we use a non-vendored version. Vendoring means that
+you store your dependencies locally. This means you are in control of
+your dependencies. You don’t need to pull them from a remote. Even if
+one or more of your dependencies One of the more famous examples is Lua.
+The Lua foundation actually recommend vendoring your Lua dependency.
+Vendoring helps with build reproducability.
+
+We will use https://github.com/terminaldweller/milla[milla] as an
+exmaple. It’s a simple go codebase.
+
+[source,dockerfile]
+----
+FROM alpine:3.19 as builder
+RUN apk update && \
+ apk upgrade && \
+ apk add go git
+WORKDIR /milla
+COPY go.sum go.mod /milla/
+RUN go mod download
+COPY *.go /milla/
+RUN go build
+
+FROM alpine:3.19
+ENV HOME /home/user
+RUN set -eux; \
+ adduser -u 1001 -D -h "$HOME" user; \
+ mkdir "$HOME/.irssi"; \
+ chown -R user:user "$HOME"
+COPY --from=builder /milla/milla "$HOME/milla"
+RUN chown user:user "$HOME/milla"
+ENTRYPOINT ["home/user/milla"]
+----
+
+The first docker image build is fairly simple. We copy the source code
+in, get our dependencies and build a static executable. As for the
+second stage of the build, we simply put the executable into a new base
+image and we are done.
+
+The second build which is a vendored build with a golang distroless
+base. We copy over the source code for the project and all its
+dependencies and then do the same as before.
+
+[source,dockerfile]
+----
+FROM golang:1.21 as builder
+WORKDIR /milla
+COPY go.sum go.mod /milla/
+RUN go mod download
+COPY *.go /milla/
+RUN CGO_ENABLED=0 go build
+
+FROM gcr.io/distroless/static-debian12
+COPY --from=builder /milla/milla "/usr/bin/milla"
+ENTRYPOINT ["milla"]
+----
+
+Below You can see an example docker compose file. Milla can optionally
+use a postgres database to store messages. We also include a pgadmin
+instance. Now let’s talk about the docker compose file.
+
+[source,yaml]
+----
+services:
+ terra:
+ image: milla_distroless_vendored
+ build:
+ context: .
+ dockerfile: ./Dockerfile_distroless_vendored
+ deploy:
+ resources:
+ limits:
+ memory: 128M
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "100m"
+ networks:
+ - terranet
+ user: 1000:1000
+ restart: unless-stopped
+ entrypoint: ["/usr/bin/milla"]
+ command: ["--config", "/config.toml"]
+ volumes:
+ - ./config.toml:/config.toml
+ - /etc/localtime:/etc/localtime:ro
+ cap_drop:
+ - ALL
+ runtime: runsc
+ postgres:
+ image: postgres:16-alpine3.19
+ deploy:
+ resources:
+ limits:
+ memory: 4096M
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "200m"
+ restart: unless-stopped
+ ports:
+ - "127.0.0.1:5455:5432/tcp"
+ volumes:
+ - terra_postgres_vault:/var/lib/postgresql/data
+ - ./scripts/:/docker-entrypoint-initdb.d/:ro
+ environment:
+ - POSTGRES_PASSWORD_FILE=/run/secrets/pg_pass_secret
+ - POSTGRES_USER_FILE=/run/secrets/pg_user_secret
+ - POSTGRES_INITDB_ARGS_FILE=/run/secrets/pg_initdb_args_secret
+ - POSTGRES_DB_FILE=/run/secrets/pg_db_secret
+ networks:
+ - terranet
+ - dbnet
+ secrets:
+ - pg_pass_secret
+ - pg_user_secret
+ - pg_initdb_args_secret
+ - pg_db_secret
+ runtime: runsc
+ pgadmin:
+ image: dpage/pgadmin4:8.6
+ deploy:
+ resources:
+ limits:
+ memory: 1024M
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "100m"
+ environment:
+ - PGADMIN_LISTEN_PORT=${PGADMIN_LISTEN_PORT:-5050}
+ - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL:-devi@terminaldweller.com}
+ - PGADMIN_DEFAULT_PASSWORD_FILE=/run/secrets/pgadmin_pass
+ - PGADMIN_DISABLE_POSTFIX=${PGADMIN_DISABLE_POSTFIX:-YES}
+ ports:
+ - "127.0.0.1:5050:5050/tcp"
+ restart: unless-stopped
+ volumes:
+ - terra_pgadmin_vault:/var/lib/pgadmin
+ networks:
+ - dbnet
+ secrets:
+ - pgadmin_pass
+networks:
+ terranet:
+ driver: bridge
+ dbnet:
+volumes:
+ terra_postgres_vault:
+ terra_pgadmin_vault:
+secrets:
+ pg_pass_secret:
+ file: ./pg/pg_pass_secret
+ pg_user_secret:
+ file: ./pg/pg_user_secret
+ pg_initdb_args_secret:
+ file: ./pg/pg_initdb_args_secret
+ pg_db_secret:
+ file: ./pg/pg_db_secret
+ pgadmin_pass:
+ file: ./pgadmin/pgadmin_pass
+----
+
+We are assigning memory usage limits for the containers. We are also
+limiting the size of the logs we are keeping on disk. One thing that we
+did not talk about before is the networking side of compose. As can be
+seen, the postgres and pgadmin container share one network while the
+postgres container and milla share another network. This makes it so
+that milla and pgadmin do not have access to each other. This is inline
+with principle of least privilege. Milla and pgadmin don’t need to talk
+to each other so they can’t do that. Also we refrain from using host
+networking. We are also binding the open ports to the host’s localhost
+interface. This does not let us connect to the endpoints directly. In
+our example we don’t need the ports to be exposed to the internet but we
+will need access to them. What we can do is bind the open ports to the
+host’s localhost and then use ssh to forward the ports onto our own
+machine, assuming the docker host is a remote.
+
+[source,sh]
+----
+ssh -L 127.0.0.1:5460:127.0.0.1:5455 user@remotehost
+----
+
+While building milla, for the second stage of the build, we made a
+non-privileged user and our now mapping a non-privileged user on the
+host to that user. We are removing all capabilities from milla since
+milla will be making requests and has no server functionality. Milla
+will only need to bind to high-numbered ports which does not require a
+special privileges. We run both postgres and milla with gvisor’s runsc
+runtime since it’s possible to do so. Finally we use docker secrets to
+put the secrets into the container’s runtime environment.
+
+Now onto the attestations. In order to view the SBOM for the image we
+will use docker https://docs.docker.com/scout/install/[scout].
+
+[source,sh]
+----
+docker scout sbom milla
+docker scout sbom milla_distroless_vendored
+----
+
+The SBOMs can be viewed
+https://gist.github.com/terminaldweller/8e8ecdcb68d4052aecb6804823648b4d[here]
+and
+https://gist.github.com/terminaldweller/f4ede7122f159506f8e6e6be2bfd6a8b[here]
+respectively.
+
+Now lets look at the provenance attestations.
+
+[source,sh]
+----
+docker buildx imagetools inspect terminaldweller/milla:main --format "{{ json .Provenance.SLSA }}"
+----
+
+And
+https://gist.github.com/terminaldweller/033ae07a9e685db85b18eb822dea4be3[here]
+you can look at the result.
+
+=== Further Reading
+
+* https://manpages.debian.org/bookworm/manpages/cgroups.7.en.html[man 7
+cgroups]
+* system containers using https://github.com/lxc/incus[lxc/incus]
+* https://katacontainers.io/[katacontainers]
++
++
+timestamp:1716163133
++
+version:1.0.0
++
+https://blog.terminaldweller.com/rss/feed
++
+https://raw.githubusercontent.com/terminaldweller/blog/main/mds/securedocker.md
++
diff --git a/put_in_db.js b/put_in_db.js
index e641187..af0a5ad 100644
--- a/put_in_db.js
+++ b/put_in_db.js
@@ -68,6 +68,14 @@ var blogs = [
keywords: ["NTP", "NTS", "SOCKS5"],
lastUpdatedAt: Date.now(),
},
+ {
+ title: "Docker, Linux, Security. Kinda.",
+ slug: "docker_linux_security",
+ body: fs.readFileSync(path.join(__dirname) + "/mds/securedocker.md"),
+ teaser: fs.readFileSync(path.join(__dirname) + "/mds/securedocker.txt"),
+ keywords: ["docker", "linux", "security"],
+ lastUpdatedAt: Date.now(),
+ },
];
db.blogposts.insertMany(blogs);