Previously I talk about using āIT-Toolsā to stop data leaks in Engineering teams⦠now Iāll demonstrate the steps an Engineer can take to security harden a workload in Kubernetes.. specifically a third-party web application for which IT-Tools fits quite nicely, and it can be quite common to deploy third-party apps.
DevOps today usually includes security in some form aka Devsecops. All the benefits of DevOps but it encompasses security as a integral part of the process.
Prior to all this, security was a bit of a afterthought in the engineering processes. Issues were addressed reactively. Agile focused on speed and collaboration and didnāt fully integrate security or know how to.
It seems obvious but only recently have wider IT governance, risk, and compliance frameworks begun to recognize the importance of integrating security in the software lifecycles. Some even mention DevSecOps by name e..g NIST Cybersecurity Framework (CSF), ISO/IEC 27001 (e.g. principle of secure coding), upcoming PCI DSS 4.0.
ā¦
Back to our app: IT-Tools⦠itās an open source web application. We canāt exactly apply all DevSecOps principles can we?
But we can do things to further reduce risks/attack surface. A nice list of guides to help can be found here https://github.com/infoslack/awesome-web-hacking
If you donāt have have prior web technology experience.. try having a speaking to a devs who often possess a deeper understanding of web technologies and can be helpful at guiding what controls to apply instead of throwing things against a wall.
After looking through how IT-Tools works and setting up a test environment. Hereās a list of things I found suitable:
Content Security Policy was introduced back in 2012, surprisingly itās still a unused tool.
It was introduced to curb vulnerabilities like XSS. Without it an attacker could execute/load arbitrary scripts and to give them a even greater attack surface.
My favorite use of XSS is to replace the page with a login screen. Imagine being sent a legitimate link to tools.yourorg.com, seeing a login screen and thinking nothing of it. Made worse if your password manager has auto-complete enabled.
XSS opens so many possibilities.. imagine..
A good Security Engineerās will know how to configure CSP to mitigate problems like these⦠all while preserving core functionality. Hereās a nice generator tool you can use to help you https://report-uri.com/home/generate.
Content-Security-Policy: default-src 'self'
i.e. This policy tells the browser, anything via self can be loaded. Anything outside of this rule gets blocked by the browser, again if thereās a XSS this will limit what is possible.
Looking at the Dockerfile, (https://github.com/CorentinTh/it-tools/blob/main/Dockerfile) indicates the application is nothing more than a static website.
Itās base image is nginx, naturally the pod should never initiate an external connection under normal circumstances. Weāll use NetworkPolicy rule to enforce this.
Like I mentioned above, the apps been developed already.
This might presents a additional risk.. third-party apps pose a attractive target to attackers; itās a easy way into many organizations at once.
Some open-source projects can be modified by anybody, or maintainer can be manipulated financially and inject malicious code. Not to mention the thousands of dependencies a typical app utilizes these days - where weāve previously seen supply chain attack.
Is it an impossible task to guard against? No, tthere are some things we can do to mitigate some of the risks posed here.
We have to trust stuff at some stage. I think a pragmatic approach would be to build our own container image from a commit hash - pinning itās code and dependencies (like package-lock.json).
Seccomp stands for Secure Computing and integral to Linux containerization, together with Namespaces, cgroups and SELinux. It is a Linux feature used to restrict the set of system calls that an application are allowed.
Docker (although not k8s default container runtime) disables around 44 syscalls (over 300 are available). Each runtime have a default Seccomp profile which can differ. Default profiles are pretty easy to find and useful when determining your workloads compatibility.
Interestingly default policies are not enabled by default in Kubernetes however you can easily set this up after testing compatibility with your workloads. (Requires v1.27+)
ChatGPT says: āAppArmor is a crucial component of Linux security, providing mandatory access control (MAC) by confining individual programs within defined security profiles.
Profiles define what actions an application can perform, including file access, network communication, and system calls.ā
Nice so we can find/create a custom AppArmor profile tailored specifically for the nginx container. This profile would define strict rules governing the nginx processās behavior, ensuring that it only accesses the necessary files and resources required to serve static web content.
apparmor
#include <tunables/global>
profile nginx_profile {
# Allow read access to static web content
/var/www/html/** r,
# Allow read access to nginx configuration files
/etc/nginx/nginx.conf r,
/etc/nginx/conf.d/** r,
# Allow network access for serving HTTP traffic
network inet tcp,
# Allow DNS resolution for hostname resolution
network inet domain,
# Allow access to necessary system libraries
/usr/lib/** mr,
# Allow access to essential system resources
capability sys_chroot,
capability setgid,
capability setuid,
# Deny access to potentially dangerous capabilities
deny capability dac_override,
deny capability dac_read_search,
deny capability fowner,
deny capability fsetid,
deny capability kill,
deny capability mknod,
deny capability sys_admin,
deny capability sys_boot,
deny capability sys_module,
deny capability sys_ptrace,
deny capability sys_rawio,
deny capability sys_time,
deny capability sys_tty_config
}It allows read access to the nginx configuration files (/etc/nginx/nginx.conf and /etc/nginx/conf.d/) and the static web content directory (/var/www/html/). It also permits network access for serving HTTP traffic and DNS resolution.
Also granting access to essential system libraries (/usr/lib/**) and capabilities necessary for nginx operation, such as sys_chroot, setgid, and setuid. Meanwhile, it explicitly denies access to potentially dangerous capabilities that are unnecessary for nginx, such as sys_admin, sys_rawio, and sys_ptrace.
Remember the principle of least privilege? It ensures containers run with the minimum permissions necessary to perform their intended tasks
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx-container
image: nginx:latest
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
ports:
- containerPort: 80
Here we have a Kubernetes pod (nginx-pod) running a single container (nginx-container) based on the nginx:latest image⦠the application doesnāt need root so the container doesnāt get r00t:
runAsNonRoot: true: This setting ensures that the nginx container runs as a non-root user, rather than with root privileges. By running as a non-root user, the containerās access to system resources and potentially sensitive files is restricted, reducing the impact of any security vulnerabilities or exploits.
runAsUser: 1000: We specify a specific non-root user ID (UID) for the container to run as. This further limits the containerās access rights and ensures that it operates within a confined environment.
readOnlyRootFilesystem: true: Setting the root filesystem to read-only prevents any writes to the root filesystem within the container. This adds an extra layer of security by mitigating the risk of unauthorized modifications to critical system files or configurations.
Our app might be served to our internal users and they will use a VPN. So we donāt necessarily need TLS.
But imagine a scenario where the site is served publicly.. TLS becomes necessary to prevent MITM attacks⦠Someone in the middle like a rogue ISP can snoop and also modify the contents of the page dynamically⦠who remembers ISPs injecting ads into our pages in 2000ās?
I will skip setting up TLS here, you can override nginxās default config or setup a sidecar container to serve the app with TLS.
In another post I will demo and publish a repo with all the mentioned rules in a live environment.