Skip to content

Instantly share code, notes, and snippets.

@egberts
Forked from cfm/README.md
Created August 21, 2023 06:46
Show Gist options
  • Save egberts/89a499a16a8f90b34102919e1819c147 to your computer and use it in GitHub Desktop.
Save egberts/89a499a16a8f90b34102919e1819c147 to your computer and use it in GitHub Desktop.
Adapting the twelve-factor methodology for "Qubes-native" multi-VM applications: a preliminary sketch

Adapting the twelve-factor methodology for "Qubes-native" multi-VM applications: a preliminary sketch1

Introduction

Virtualization is the conceptual technology on which modern services (server applications) are built. Whether an application happens to run on a fully- or para-virtualized VM2 or is containerized—or even runs on a “bare-metal” physical server after all—most modern services are designed in isolated, replicated, disposable components on commodity hardware.3 The “twelve-factor methodology” (2011) is an influential articulation of the principles that tend to be adopted, more or less explicitly, by applications designed and deployed in this way. “Cloud-native” is a more-recent articulation and expansion of many of the same principles.

Virtualization is also the conceptual as well as literal technology on which Qubes OS’s security-by-compartmentalization desktop (client-side) environment is built. However, because most Qubes users run “normal” Linux applications (Firefox, Thunderbird, Vocal, Hypatia, etc.) most of the time, there seems to be only niche interest in considering Qubes a unique environment for designing desktop applications, not just for running them.

If virtualization has been so influential in the evolution of server-side architecture, we should wonder how it might also influence the evolution of client-side architecture—at least for specialized applications, such as the SecureDrop Workstation, that require its security properties in the first place.

Working definitions and hypotheses

A “cloud-native” (server) application consists of isolated, replicated, disposable components that talk to one another in predefined ways, especially with regard to the flow of data and the persistence of state.

A “Qubes-native” (desktop) application consists of isolated, replicated, disposable components that talk to one another in predefined ways, especially with regard to the flow of data and the persistence of state.

The factors are implementation patterns that follow logically from these properties of isolation, disposability, and predefinition. Where these properties apply in common to “cloud-native” and “Qubes-native” applications, both classes of applications can follow these patterns and share tools4 to help implement them—even if they have different motivations for these properties.

What is the “twelve-factor” methodology?5

In the modern era, software is commonly delivered as a service: called web apps, or software-as-a-service. The twelve-factor app is a methodology for building software-as-a-service apps that:

  • Use declarative formats for setup automation, to minimize time and cost for new developers joining the project;
  • Have a clean contract with the underlying operating system, offering maximum portability between execution environments;
  • Are suitable for deployment on modern cloud platforms, obviating the need for servers and systems administration;
  • Minimize divergence between development and production, enabling continuous deployment for maximum agility;
  • And can scale up without significant changes to tooling, architecture, or development practices.

The twelve-factor methodology can be applied to apps written in any programming language, and which use any combination of backing services (database, queue, memory cache, etc).

What are the twelve factors?6

Factor Description
1. Codebase There should be exactly one codebase for a deployed service with the codebase being used for many deployments.
2. Dependencies All dependencies should be declared, with no implicit reliance on system tools or libraries.
3. Configuration Configuration that varies between deployments should be stored in the environment.
4. Backing services All backing services are treated as attached resources and attached and detached by the execution environment.
5. Build, release, run The delivery pipeline should strictly consist of build, release, run.
6. Processes Applications should be deployed as one or more stateless processes with persisted data stored on a backing service.
7. Port binding Self-contained services should make themselves available to other services by specified ports.
8. Concurrency Concurrency is advocated by scaling individual processes.
9. Disposability Fast startup and shutdown are advocated for a more robust and resilient system.
10. Development/ production parity All environments should be as similar as possible.
11. Logs Applications should produce logs as event streams and leave the execution environment to aggregate.
12. Admin processes Any needed admin tasks should be kept in source control and packaged with the application.

Some subsequent articulations extend this model with additional factors, for example:7

Factor Description
13. API “Define the service contract first”8; even first-party applications consume the same API as everyone else.
14. Telemetry Monitor holistic service “health” over time, not just errors and exceptions.
15. Authentication and authorization Authentication and access controls appropriate to every layer of the stack.

Which factors are and are not relevant in a Qubes OS desktop environment?

LEGEND
The factor is relevant in Qubes OS, and the SecureDrop Workstation currently makes use of it.
¾ The factor is relevant in Qubes OS. The SecureDrop Workstation currently makes explicit use of it, with limitations or edge cases for future work.
½ The factor is relevant in Qubes OS. The SecureDrop Workstation currently makes partial or implicit use of it and could expand it.
¼ The factor is potentially relevant in Qubes OS, with caveats.
The factor is not relevant in Qubes OS.

Taking the current (→ idealized) SecureDrop Workstation as an example:

Factor Application
1. Codebase ✓—The securedrop-{workstation,client,export,sdk,proxy} repositories are used in all deployments, in all environments.
2. Dependencies ¾—The provisioned sd-* VMs and their installed packages manage most of their own dependencies independent of the underlying host, with some exceptions we hope to resolve.
3. Configuration ½—Variable configuration is injected into the sd-* VMs’ filesystems during installation and during any subsequent reconfiguration.

securedrop-workstation#853 will be unblocked by QubesOS/qubes-issues#8138.
4. Backing services ½—See (6) “Processes” for state-oriented and (7) “Port Binding” for action-oriented backing services.
5. Build, release, run ✗—Not applicable. A 12-factor release involves pushing the output of a continuous-integration workflow into a continuous-deployment workflow. A Qubes-based application, like any native desktop application, will always be released by publishing an artifact for existing deployments to pull and install locally.
6. Processes ½—The SecureDrop Client application in the sd-app VM is highly stateful on files and a database on the same filesystem and mounted within the same VM as the running application.

→ These state-oriented functions could be abstracted out into other backing services to separate their concerns (and shrink their attack surfaces) further.
7. Port binding ½—The SecureDrop Client application in the “air-gapped” (networkless) sd-app VM makes use of a couple of “external” services, which are provided by other VMs and called via qrexec RPC calls rather than ports or sockets.

→ We’ve considered different approaches for generalizing these action-oriented functions to make them more robust and extensible.
8. Concurrency ¼—Potentially applicable, although concurrency on Qubes OS serves further isolation9 as much as increased performance.
9. Disposability ½—Disposable VMs are used to isolate “view” and “export” operations.

→ With backing stores and runtime configuration factored out, the service VMs running the SecureDrop Client and securedrop-proxy could also be stateless and disposable.

If fully stateless and disposable, we could change our conceptual model for provisioning the Workstation from enforcing idempotent state (e.g., salt state.highstate) to either (a) replacing images and configuration in place or (b) wiping them and provisioning them from scratch every time (like terraform destroy && terraform apply).
10. Development/ production parity ✓—Pretty much!—parameterized on which Yum and Apt repositories host and guest packages are fetched from, respectively.
11. Logs ✓—The sd-* VMs stream their logs to the sd-log VM, which is a log sink just like a syslog server.
12. Admin processes ½—Via sdw-admin, except for cases such as clipboard policy where we recommend the use of native Qubes tooling.

→ Further administration depends on further work on (3) “Configuration” and (4) “Backing Services”.
13. API ✓—The SecureDrop Server’s Journalist API is the foundation of the SecureDrop Client.
14. Telemetry ¼—Potentially desirable for individual VMs but not for dom0, which in Qubes OS does not have network connectivity. Not applicable at all for the SecureDrop Workstation: For both technical and organizational security reasons, we’re no more likely to aggregate logs or telemetry for real-time monitoring of an organization’s SecureDrop Workstations than we are for on-contract SecureDrop Servers.10
15. Authentication and authorization ✓—Yes, on a comprehensive and rigorous threat-model.

Conclusion

The premise of the SecureDrop Workstation project is that Qubes OS is a platform for building secure multi-VM applications. The foundation of that platform—virtualization—is originally and fundamentally server technology.

Therefore, a secure multi-VM application such as the SecureDrop Workstation isn’t straightforwardly a “desktop” or “client” application. It’s a collection of “server” services—that just so happens to have a native GUI frontend served via the Qubes GUI subsystem, rather than a Web frontend served to a Web browser.

For future work

In addition to the limitations discussed above:

  • Is there a Qubes-specific factor we can define, such as inter-VM policy or permissions, either (a) beyond the standard configuration factor and the supplemental authentication/authorization factor or (b) by composing multiple factors? How might this factor be related to other trends in server and network architecture, such as network ACLs and service-specific policies in cloud environments?11

    • Alternatively, this might call for a generalization of the "split" service architecture exemplified by split GPG.

References

Changelog

16‒17 May 2023:

  • Update and streamline for publication as a working paper.
  • Incorporate FPF contributions.
  • Convert to Markdown.

3 November 2022:

  • Address FPF feedback.

26 October 2022:

  • Add a footnote re: Salt.

19 October 2022:

  • Clarify terminology.

13 October 2022: Second draft.

  • Address “extra” factors beyond the original 12-factor model.
  • Expand working definitions and hypotheses, and address the distinction between implementation patterns and motivations.

6 October 2022: First draft.

Footnotes

  1. This working paper was inspired by Michael Z.’s talk on “Building Secure Applications with Qubes OS” at the 2022 Qubes OS Summit; and has been further informed by ongoing discussions within the SecureDrop and Dangerzone teams at the Freedom of the Press Foundation, where I work, and with the Qubes OS team at Invisible Things Lab. However, except where noted otherwise, the opinions and speculations expressed here are my own—as are all assumptions, limitations, and errors.

  2. Xen, "Understanding the Virtualization Spectrum".

  3. Bias, "The History of Pets vs Cattle and How to Use the Analogy Properly".

  4. Qubes's use of Salt already proves this point: Salt is first and foremost a configuration-management tool for servers.

  5. Wiggins, "The Twelve-Factor App".

  6. Wiggins; Wikipedia, "Twelve-Factor App Methodology".

  7. Jansen, "Beyond the 12 Factors: 15-Factor Cloud-Native Java Applications".

  8. Luciani, "The Fifteen-Factor App".

  9. Or usability: e.g., bulk sanitization of documents.

  10. This has been discussed for both the Workstation and the Server.

  11. This point comes from Ro S., who observes: “If you're thinking of making a [Q]ubes-native app, one of the first things you will have to think about is which domain will be responsible for what layer, and how you will enforce that with policy.”

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment