The trend for immutable systems in Linux
Operating systems evolve continuously, with recent trends notably shifting from traditional imperative configuration to more secure and efficient models like immutable and declarative configurations. This article explores these evolving paradigms, highlighting their implications for system security and management.
Operating system and management is constantly evolving. Lately, although as far as 20 years ago, we’ve seen the market moving away from imperative configuration to immutable and declarative configuration. The benefits for security are clear: you can greatly reduce the attack surface for the OS and along with automatic updates reduce the time needed to maintain it. For clusters like Kubernetes, that also aligns the OS with the management layer for it.
However, the devil is in the details, and many of these concepts are being redefined constantly and can lead to confusion.
So what is imperative configuration and how does it differs from declarative? It involves specifying the necessary steps and commands to achieve a desired system state, typically through scripts and automation tools. All your bash and Python scripts, and some automation engines work under this paradigm.
On the other hand, declarative configuration focuses on defining the desired end state. The system’s automation layer then performs the necessary actions to achieve this state through a process known as reconciliation. Kubernetes is one of the more successful examples of this approach, automating system adjustments to maintain specified conditions, such as the number of running containers.
This leads us to the concept of immutable systems, where changes to the system state are not manually made post-deployment. Instead, the state is predefined, and the system enforces this state automatically, enhancing security and stability.
But immutable systems are not perfect. In a system using the Filesystem Hierarchy Standard by the LSB workgroup of the Linux Foundation, the passwords are stored in /etc, that will be read-only in an immutable system, and thus not suited for a user system. For that reason, immutable comes in flavors.
What is normally named immutable really is a mix of different concepts in order of balancing security, ease of use and flexibility, so that every “immutable” flavor or Linux has a different mix for that.
Declarative: We have defined declarative systems before. Infrastructure as Code is built on top of this paradigm. Kubernetes and its reconciliation loop is one of the successful examples of this, although it was already put into practice with tools such as Puppet in the past. In production, this is not as easy as it sounds. Anybody that has implemented several updates on a Kubernetes cluster or a complex configuration in Puppet understands how quickly what seems to be independent states interlace in a way that breaks the outcome. Declarative systems are many times harder to define and thus manage than traditional systems. If you can’t agree on a desired state, there is no declaration that can guide you there.
Immutable (image-based): You could think of the entire OS as an image that you put into a package , and deployed in a read-only file system or hardware so it can not be modified post-deployment except through the delivery of a new image, or via specific tooling to make changes. Rancher’s Elemental toolkit and other Kubernetes distributions use this approach due to its predictability. Immutable systems require an infrastructure to create the images that can be complex in itself, and make it more challenging to adapt to specific changes (like nodes with different hardware or software expectations). They normally can roll-back to a previous image, but you won’t be able to create a new user or change their password. Workloads run as containers to make them independent of the immutable system.
Transactional: With transactional systems, core system changes, including the configuration, are treated as transactions that are atomic and reversible. Changes are grouped together and can be rolled back, ensuring that the system can be reinstated into a previously defined working state. Transactional systems require that package dependencies are solved by the package manager and thus do not guarantee that the resolution is exactly the same for all systems, but ensure a consistent solution and a fallback.
All of them can be reproducible and idempotent. Reproducible systems will create an equivalent copy of your configuration if you run your installation process at different times, with the same versions of packages and configuration. An idempotent configuration system will generate the same exact configuration even if you apply them more than once, so it is safe to update the configuration several times. Some configurations can not be idempotent, like the UUID or SSH-key of the system, even if the rest of the configuration needs to be so.
In fact, when customers are thinking on immutable system, they are thinking about three core aspects: they need a system that can be declarative: specifying the version of each package used and making it possible to replicate on every host, transactional so that the changes can be documented, applied to a new state, stored and — if required — reverted, and lastly immutable, with a read-only root system that limits the security challenges of running the OS unattended. A system like that will ideally be also reproducible and idempotent.
In conclusion, the shift from imperative to declarative and immutable configurations in Linux system management marks a key development towards enhancing security, stability, and efficiency in modern computing environments. Each configuration type presents unique benefits and inherent challenges and is permeating the Linux development:
- Immutable Systems: Enhance security with a read-only state but limit dynamic changes.
- Declarative Configurations: Offer efficient management through state automation but require clear consensus on the desired state.
- Transactional Systems: Provide rollback capabilities to maintain system integrity, though they demand complex dependency resolutions.
As technology evolves, understanding these nuances is key to get the best out of them. System administrators and developers must adapt their strategies to control these configurations effectively, ensuring they fulfill specific operational requirements. Configurations today and in the future highlights the importance of staying informed and adaptable, getting the most out of the systems involved.
Explore Practical Applications: To see these principles in action, consider exploring SUSE Linux Micro. As a leading solution widely utilized by Rancher and SUSE Edge, it offers a practical demonstration of these advanced system management strategies, available for deployment across any cloud or datacenter.
