<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  
  <channel>
    
    
    
    
    <title>OpenStack on Consensus Enterprises Blog</title>
    <link>https://consensus.enterprises/tags/openstack/</link>
    <description>Recent content tagged 'OpenStack' on the Consensus Enterprises Blog.</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-CA</language>
    <managingEditor>info@consensus.enterprises (The Consensus Team)</managingEditor>
    <webMaster>tech@consensus.enterprises (Consensus Infrastructure)</webMaster>
    <copyright>Copyright 2025 Consensus Enterprises International Inc.</copyright>
    <lastBuildDate>Tue, 06 Jun 2023 09:00:00 -0400</lastBuildDate>
    <image>
      <url>https://consensus.enterprises/images/consensus-blog-banner.png</url>
      <title>OpenStack on Consensus Enterprises Blog</title>
      <link>https://consensus.enterprises/tags/openstack/</link>
    </image>
    
        <atom:link href="https://consensus.enterprises/tags/openstack/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Aegir5: Feature parity between Aegir3 and Aegir5</title>
      <link>https://consensus.enterprises/blog/aegir5-feature-parity/</link>
      <pubDate>Tue, 06 Jun 2023 09:00:00 -0400</pubDate>
      
      
      <guid isPermaLink="false">Aegir5: Feature parity between Aegir3 and Aegir5 on Consensus Enterprises Blog published Tue, 06 Jun 2023 09:00:00 -0400</guid>
      
      <description>In previous posts, we’ve covered our Kubernetes framework for an alternative back-end to Aegir5, as well as the front-end Tasks and Operations and Clusters, Projects, Releases, and Environments. We also discussed the Queue architecture that ties the front- and back-ends together. This time, let’s consider the planned feature parity between Aegir 3 and Aegir 5.
In Aegir3, Servers only have a “verify” task. This ensures that the front end can connect to the server over SSH. The new model will …</description>
      <content:encoded>In previous posts, we’ve covered our Kubernetes framework for an alternative back-end to Aegir5, as well as the front-end Tasks and Operations and Clusters, Projects, Releases, and Environments. We also discussed the Queue architecture that ties the front- and back-ends together. This time, let’s consider the planned feature parity between Aegir 3 and Aegir 5.
In Aegir3, Servers only have a “verify” task. This ensures that the front end can connect to the server over SSH. The new model will introduce the analogous Cluster entity. This will work similarly, ensuring that the front-end can connect to the Kubernetes cluster.
Platforms, for their part, generally have two tasks in Aegir 3: verify, and migrate sites. The Verify task largely is responsible for deploying the platform, as well as ensuring proper file permissions and so forth.
Aegir5 represents a notable departure in this area. We’ve introduced two different entities to represent different aspects of what a Platform does in Aegir3.
First, we have Projects, which are effectively a codebase- a git repository somewhere with an application that’s under development, evolving and improving. On top of that is a Release, which in the Kubernetes backend amounts to building a new container image. This represents a snapshot of the Project at a specific point in time: a version of the application, all its dependencies, and the runtime environment config needed to run it.
In the short-term, our focus is on this cloud-native use-case, but the idea of Projects and Releases is applicable even in a more traditional VM-based scenario. At the infrastructure level, Clusters is the current target, but Aegir will support a more traditional Server as well, allowing Projects to be deployed onto varying infrastructure models.
In Aegir3, Sites have a CRUD suite of tasks that include installing, verifying, upgrading and deleting. In Aegir5, this will be represented by Environments, into which we can deploy, update and delete the application. From the front end, this will look almost identical, but of course in the Kubernetes context these represent a running instance of the application: a container image of a particular Release, on a given Cluster.
There is one more important distinction at this level. Aegir3 relies extensively on Drupal’s multisite capabilities. With Aegir5, we are setting aside that functionality almost entirely. Instead, we treat each site as standalone. This allows for support of large sites with complex development workflows. However, we can also track which sites use a given image. As a result we can (with a single operation) trigger migrations/updates for all the instances that are using that image.
Aegir3 relies heavily on a bespoke task queue. As described previously, these Tasks have become Operations in Aegir5. They already have a log of the backend output. Operations in turn are composed of Tasks, which in Aegir5 are more granular, configurable steps in a larger whole. For example, writing a virtual host configuration, or setting up a HTTPS certificate.
As discussed, we’ve modernized the task queue itself to use Celery, which is built atop RabbitMQ. This stack replaces the bespoke implementation and unlocks a more distributed “control plane” for the Aegir system.
In addition to the task queue, Aegir3 also includes queues for running cron, taking scheduled backups, and so forth. Celery is certainly capable of implementing such queues. However, these are not an immediate priority.
One feature from Aegir3 that we would like to incorporate is the ability to retry failed tasks. However, this may not make sense in a Kubernetes context.
Backup and restore are important tasks for Aegir. In the long run, Aegir5’s Kubernetes backend will probably want to do volume snapshots using a tool like Valero.
However, to keep things simple to start, we will operate similarly to how we do this in Aegir3, using an SQL dump and file tarball, a model which has served us well all these years.
Cloning a site, in the long run, will be a composition of deploying from a snapshot/backup, taken immediately. Here again, the composition of this kind of operation becomes very similar to Aegir3. However, we can also simply deploy a new site, and then synchronize the database and files from the source site.
Disabling a site will be a matter of running a job that rewrites the vhost to point to a static page, similarly to how Aegir3 does it now.
As previously discussed in the Frontend Low-level Architecture post, the password reset functionality is much improved, by simply providing a “login to site” button.
URL aliases and HTTPS capabilities are both already handled within the Kubernetes backend via the ingress and certificate manager services. These will be exposed via the Drupal UI as configuration options when creating an Environment to deploy a Release.
The fundamental concepts of Aegir3 map quite readily onto the new Aegir5 architecture. There are some functional changes to modernize the overall framework, but from an end-user standpoint, the user experience (UX) of working with an Aegir5 system should feel quite familiar.
The mapping described here shows how the new back-end and queue components integrate into this UX structure. In our next post, we’ll lay out our plan to move ahead and implement the missing pieces to get a fully functional MVP Aegir5 system.
We are excited to be talking about this effort more publicly, and even more so to see more engagement with the Aegir5 project from the wider community. Let us know what you think and how you want to get involved!
</content:encoded>
    </item>
    
    <item>
      <title>Aegir5 &#43; Pitch-burgh</title>
      <link>https://consensus.enterprises/blog/aegir5-pitchburgh/</link>
      <pubDate>Wed, 31 May 2023 09:00:00 -0300</pubDate>
      
      
      <guid isPermaLink="false">Aegir5 &#43; Pitch-burgh on Consensus Enterprises Blog published Wed, 31 May 2023 09:00:00 -0300</guid>
      
      <description>See our recent Aegir5 Roadmapping series for more background!  Recently, Dries announced an exciting event at the upcoming DrupalCon Pittsburgh: Shark Tank meets Drupal: pitch your best innovation ideas/):
 Announcing “Pitch-burgh”, an innovation contest at DrupalCon Pittsburgh, where members of the Drupal community can pitch their ideas to receive funding. […] The entrepreneurs give short 2-3 minute presentations in the hopes of securing funding for their idea.
 Since we’re actively pursuing …</description>
      <content:encoded>See our recent Aegir5 Roadmapping series for more background!  Recently, Dries announced an exciting event at the upcoming DrupalCon Pittsburgh: Shark Tank meets Drupal: pitch your best innovation ideas/):
 Announcing “Pitch-burgh”, an innovation contest at DrupalCon Pittsburgh, where members of the Drupal community can pitch their ideas to receive funding. […] The entrepreneurs give short 2-3 minute presentations in the hopes of securing funding for their idea.
 Since we’re actively pursuing partners and funding for Aegir5 development, this seemed like it could be a good opportunity. If nothing else, it’d give us a chance to develop a succinct message to describe this initiative.
We’re pretty happy with the results. We hope you like it too (and read on below for more about the making of, and intention behind our pitch):
 Bridging to the Future: A plan to bring Aegir 5 to the Drupal community from Consensus Enterprises on Vimeo.
Description: Consensus Enterprises is seeking funds to match its own investment in building Aegir 5: an application-agnostic, modern, and open-source community-owned hosting tool that works with Drupal 10. This will offer a migration path for Aegir 3 users, and will also enable management of non-Drupal sites and applications with entire software stacks. This funding will help us reach an alpha MVP more quickly, opening the door for other contributors in the community to also start developing the application.
We had recently started working with an absolutely fantastic marketing consultant, Zack (storypanda.ca). When we asked him about it, he was quick to recommend Rob, with whom he’d collaborated successfully on previous projects. Rob (robspence.tv) is an amazing filmmaker and, interestingly, also a real-life cyborg.
They both quickly agreed to help, so we started figuring out what we wanted to say. Zack led some initial brainstorming, and gave us some homework in the form of a questionnaire to help the Consensus-Aegir team to articulate our vision for the project.
In the meantime, Rob had us scout locations within our respective homes. He also prompted us to start gathering some visual elements to incorporate into the video, so that we wouldn’t just be talking heads.
Zack came up with a draft script that touched on all the important topics we’d come up with. After a round of revisions, we were ready to shoot.
None of us felt particularly comfortable in front of the cameras, even if they were just the ones in our phones. Rob came through again, putting us at ease with witty banter, and confidence earned over decades of shooting and editing videos.
With the shooting done, Rob put together a rough-cut. This was eye-opening, as we could finally get a sense of what the final product would look like. Several edits later, based on feedback from the team and Zack, we had our final product.
To be frank, we’ve found it challenging to distill a succinct message in terms of our vision of Aegir, what it can be for the community, and what we want to do with it.
“Here’s what we’re proposing…” Christopher begins, about 30 seconds into the video. He goes on to describe the urgent need to sunset Aegir3 and replace it with Aegir5. We’ve been cultivating this for several years, but we recognize the need to re-open the Aegir project to community participation and contribution.
In the video, we identify a few deliverables, which focus on releasing Aegir5 back into the Drupal community at large. The core of this milestone is to wire up the functional components we’ve built into a coherent minimal viable product (MVP). This will address the immediate use-case we’re seeing in our own work, while allowing the flexibility to expand functionality to other cases.
Fundamentally, the MVP will provide a functional Drupal app hosting platform which can replace Aegir3, ideally before Drupal 7 goes EOL. In the Alpha MVP stage, the goal is to release a stable “core” of Aegir5, a developer-ready foundation on which to build further. Improving the developer experience (DX) in Aegir5 is a key design goal, since we want the system to support a wide array of features we can’t build all on our own.
To that end, we plan to review, update, and improve our documentation, continue building out example modules which demonstrate how to leverage the underlying tools, as well as a comprehensive test suite. We view testing as both a quality control, guarding against regressions and other breakage, but also a means to illustrate how the system behaves. We’re working in the open on this, so feel free to check out the milestone details and engage with us on the GitLab project anytime :)
Once we complete the Alpha MVP milestone, we will start incorporating feedback from the existing Aegir developer community (shout-outs to Omega8.cc, DevShop, and InitFour.nl!) and beyond. We’ve already had some great conversations with existing Aegir3 users, and we plan to evolve the Beta MVP (and subsequent) milestone(s) based on the interest and feedback we gather in this process.
Since the original Hostmaster evolved into Aegir over a decade ago, many commercial Drupal hosting providers (Acquia, Pantheon, Platform.sh, etc) have come to the fore and serve a valuable role in the ongoing growth of Drupal on the web. As strong open source advocates, we believe it’s important to have an open, free alternative to commercial providers where we can address the additional use-cases in this space (eg. self-hosters, SaaS owners, etc.) and to help keep the Drupal devOps community open and growing.
Watch this space for an upcoming series to talk in more detail about these use-cases and how we imagine the ongoing evolution of Aegir5 :)
Consensus plans to continue being a community steward for Aegir, as we feel passionate about it’s value both to ourselves and as a community. We look forward to wider participation in this effort. Please get in touch if you’re interested in supporting Aegir5!
Wish us luck at DrupalCon Pitch-burg!
</content:encoded>
    </item>
    
    <item>
      <title>Aegir5: Kubernetes Backend integration</title>
      <link>https://consensus.enterprises/blog/aegir5-kubernetes-backend/</link>
      <pubDate>Tue, 16 May 2023 09:00:01 -0500</pubDate>
      
      
      <guid isPermaLink="false">Aegir5: Kubernetes Backend integration on Consensus Enterprises Blog published Tue, 16 May 2023 09:00:01 -0500</guid>
      
      <description>In previous posts we covered how the Frontend and queue mechanisms can talk with the Backend. We also covered the stand-alone work we’ve been doing within Drumkit to support Drupal on Kubernetes. In this post, we’ll discuss how we plan to integrate this new Backend into the existing Aegir 5 architecture.
To integrate the Kubernetes Backend into Aegir 5, we will need to build new top-level entities (see this earlier post about Clusters, Projects, Releases, and Environments) for the Frontend. …</description>
      <content:encoded>In previous posts we covered how the Frontend and queue mechanisms can talk with the Backend. We also covered the stand-alone work we’ve been doing within Drumkit to support Drupal on Kubernetes. In this post, we’ll discuss how we plan to integrate this new Backend into the existing Aegir 5 architecture.
To integrate the Kubernetes Backend into Aegir 5, we will need to build new top-level entities (see this earlier post about Clusters, Projects, Releases, and Environments) for the Frontend. These entities are composed almost entirely of Operations.
The Tasks on the Frontend will primarily gather the variables needed to generate the templates in Drumkit on the Backend. These are passed through the Queue system to the Backend. The Backend in turn instantiates the configuration files, and runs the appropriate kubectl commands to deploy the various components into the Kubernetes cluster.
Drumkit currently has make targets that initialize an Environment and deploy a Project Release to it, among other things. We will need to add a Drumkit Backend to extend dispatcherd to issue these make targets, passing in the Frontend variables. Having dispatched the job, the Backend will then gather output and send it back to the Frontend.
In previous editions of Aegir, we sometimes saw the split-brain problem arise as a result of the Frontend and Backend sharing responsibility for the state of the system.
In Aegir5, the Frontend is intended to be canonical with regards to the data about the state of a running application. Aegir manages the Environment, consisting of the application state (files &#43; database).
The Project incorporates the infrastructure Kubernetes resources required to host the application. Drumkit provides commands to initialize a project with such resource definitions.
We are working on getting more specific about the tasks required to implement this in a new roadmap ticket. Our next post in the series will compare Aegir3 and Aegir5 from a features standpoint, after which we’ll discuss the plan to get from here to there, once we’ve established a clear roadmap.
</content:encoded>
    </item>
    
    <item>
      <title>Aegir5: Queue Architecture</title>
      <link>https://consensus.enterprises/blog/aegir5-queue-architecture/</link>
      <pubDate>Wed, 26 Apr 2023 09:00:00 -0500</pubDate>
      
      
      <guid isPermaLink="false">Aegir5: Queue Architecture on Consensus Enterprises Blog published Wed, 26 Apr 2023 09:00:00 -0500</guid>
      
      <description>Previously in this series, we looked at the Aegir5 front-end interface architecture, as well as the lower level entities, Tasks and Operations that provide building blocks.
As mentioned in the first part of the series, our most recent work on Aegir5 itself has been reworking the queue system. In this post, we explore this topic in more detail.
The Aegir5 queue is implemented using Celery, which is a full-featured Python-based task queue, built atop RabbitMQ. Initially we built dispatcherd which …</description>
      <content:encoded>Previously in this series, we looked at the Aegir5 front-end interface architecture, as well as the lower level entities, Tasks and Operations that provide building blocks.
As mentioned in the first part of the series, our most recent work on Aegir5 itself has been reworking the queue system. In this post, we explore this topic in more detail.
The Aegir5 queue is implemented using Celery, which is a full-featured Python-based task queue, built atop RabbitMQ. Initially we built dispatcherd which operates as the back-end queue worker. For a variety of reasons that we’ll get into later, we also added relayd to run on the front end.
dispatcherd is the Aegir5 equivalent of Drush Provision. It is responsible for writing configuration files and then running the commands that will instantiate whatever the configurations represent.
dispatcherd runs commands such as ansible playbook. It then gathers the terminal output and sends it back to the front-end. Initially, this was done using an HTTP end-point, which would update the log record of the relevant operation. This worked reasonably well, but it required HTTP access from dispatcherd to the front end.
This is where relayd comes into play. By hitting the front end with updates from the terminal output, we had to bootstrap the web UI repeatedly, putting unnecessary load on the front end. So we built an alternative solution: relayd running as a queue worker on the front end. This front end worker is very lightweight, picking up data and passing it on to an aegir:console command that can be more efficient at injecting the log results from the back end.
Once we had added relayd, we realized it presented another opportunity. Up to this point, the front end had been posting directly into the queue for dispatcherd. However, this required the front end to have credentials to the Celery queue. Since the intention was for relayd to run in the same context as the front end, we could instead simply have the front end communicate with relayd securely without providing credentials to the back-end.
In addition to a more loose coupling of all the components, this represents an improved security posture for Aegir5 overall. By removing queue credentials from the front-end UI, we reduce the risk of a vulnerability in the Drupal site leading to a compromise of the back-end infrasructure.
Having built and tested the queue architecture fairly thoroughly we are poised to tie everything together. In the next post, we explore the integration of our Kubernetes framework with the queue mechanism and existing front-end UI to create a fully functional (albeit MVP) Aegir5 implementation.
</content:encoded>
    </item>
    
    <item>
      <title>Aegir5: Front-end UI architecture</title>
      <link>https://consensus.enterprises/blog/aegir5-frontend-ui/</link>
      <pubDate>Tue, 18 Apr 2023 09:00:00 -0500</pubDate>
      
      
      <guid isPermaLink="false">Aegir5: Front-end UI architecture on Consensus Enterprises Blog published Tue, 18 Apr 2023 09:00:00 -0500</guid>
      
      <description>In our previous post, we looked at the Tasks and Operations which form the building blocks for the user interface in Aegir5. Here we’ll look at the additional entities required to support the Kubernetes-based backend framework.
It is worth noting that Aegir has always had a tension between Developer and SysAdmin use-cases. We’ll cover this in more depth in a later post. For the moment, we’re focused on the Developer use-case.
One thing to bear in mind is that Kubernetes operates quite …</description>
      <content:encoded>In our previous post, we looked at the Tasks and Operations which form the building blocks for the user interface in Aegir5. Here we’ll look at the additional entities required to support the Kubernetes-based backend framework.
It is worth noting that Aegir has always had a tension between Developer and SysAdmin use-cases. We’ll cover this in more depth in a later post. For the moment, we’re focused on the Developer use-case.
One thing to bear in mind is that Kubernetes operates quite differently than configuring and operating Nginx and MySQL directly, as we do with Aegir 3 Provision. As a result, the types of entities we are working with are going to be somewhat different. However, they will largely map to existing concepts in Aegir 3.
As seen in the diagram from the Kubernetes backend post (reproduced below), the core entities are dealing with are Clusters, Projects, Releases and Environments that we’re managing.
N.B. The terms below are how we’re currently describing the high-level components. Our goal here is to make these as natural and clear as possible. This may evolve over time, especially if we have to continuously explain what any of them mean (i.e. “Platform”).
Clusters, in this case, map fairly well to Servers. We intend to support provisioning of Clusters in the future. For the time-being, we will simply be pointing at existing Clusters to which we will want to deploy our applications.
Projects represent the codebase at a more abstract level. Whereas Releases (see below) are fully instantiated codebases, Projects represent the source of the codebase itself; usually a Git repository.
We may introduce a similar entity type, Applications, down the road. These would serve a similar purpose, but optimized for “cattle” in the SysAdmin use-case.
Devshop and the Aegir Distributions module provide similar functionality in Aegir 3.
Releases are basically the equivalent of Platforms in Aegir 3. They capture the runtime environment, with a specific version of our codebase deployed and all dependencies downloaded. In Kubernetes, these are basically container images.
Sharing a common codebase across multiple sites can be achieved by leveraging the same Release. However, unlike Platforms, we are not intending to support Drupal’s multisite capability in Aegir5.
Multisite adds a lot of complexity, especially when running in a containerized environment. It also introduces multiple security and stability concerns.
Environments become the equivalent of Sites in Aegir 3. They capture the specific configuration required to run an instance of a specific Release of the Project (or Application), along with the storage required for both the database and any uploaded files.
These are what we believe to be the basic building blocks that we need to wire up to the Drumkit Kubernetes backend. We’ve tried not to bake in too tight of a coupling to the Kubernetes backend. They ought to be re-usable for the Ansible backend, as well.
Our medium-term goal is to build a robust, reliable and flexible continuous delivery system. Some of this will likely require much more opinionated approaches. We want to keep the basic components minimally opinionated, so that they can be composed into more elaborate workflows to satisfy different use-cases (eg. SaaS operations).
So far in this series we’ve looked at the Kubernetes framework we’ve built which will form the new backend for Aegir5. We’ve also explored the Drupal content architecture that forms the front-end. In the next post we’ll look at the Queue architecture which ties the front-end and back-end together before moving on to our Roadmap for bringing the whole thing together.
</content:encoded>
    </item>
    
    <item>
      <title>Aegir5: Front-end low-level architecture</title>
      <link>https://consensus.enterprises/blog/aegir5-frontend-low-level/</link>
      <pubDate>Thu, 06 Apr 2023 09:00:00 -0500</pubDate>
      
      
      <guid isPermaLink="false">Aegir5: Front-end low-level architecture on Consensus Enterprises Blog published Thu, 06 Apr 2023 09:00:00 -0500</guid>
      
      <description>In our previous post, we talked about our recent client work building a Kubernetes-based system for hosting web applications. We’ve defined a general framework to support our development and production hosting workflows, and recognized this as a solid basis for an alternate backend to plug in to the existing Aegir5 front-end. Today we’ll take a look at the Drupal architecture underlying that front-end.
In Aegir5, the building blocks consist of Task and Operation entities. Tasks represent …</description>
      <content:encoded>In our previous post, we talked about our recent client work building a Kubernetes-based system for hosting web applications. We’ve defined a general framework to support our development and production hosting workflows, and recognized this as a solid basis for an alternate backend to plug in to the existing Aegir5 front-end. Today we’ll take a look at the Drupal architecture underlying that front-end.
In Aegir5, the building blocks consist of Task and Operation entities. Tasks represent relatively low-level reusable functionality. For example, we might have a Task for the Ansible back-end that is responsible for writing an Nginx vhost. We might then bundle that Task, along with others, in order to compose an “Install Drupal” Operation. Since the need to write a vhost is pretty common for web applications, that same Task might also be bundled into an “Install Joomla” Operation.
Operations represent the actions that a user might want to trigger. Operations are configured to contain one or more Tasks. Each Task is a standalone fieldable entity. As a result each Task is responsible for gathering whatever data it needs to run its back-end tasks. The Operation includes these Tasks as inline entities.
When we trigger an Operation, we are presented with a form that includes all the fields from the various Tasks associated with that Operation. These values, across all of the related Tasks, are marshalled and sent to the back-end.
Logs are kept at the Operation level and so the output from the back-end gets piped back into a field on the Operation. In addition to the terminal output from the back-end, we also include the return code of the operation, so that we can record whether it succeeded or not.
Another type of task is what we call an “action” task. These do not get bundled into Operations, but rather happen within a given page request. For example, instead of explicitly triggering a “password reset” task, as we do in Aegir 3, we can have a task dispatched when we click a “Log into site” button. This task runs a drush uli (via the Celery task queue), and relays the result directly back to the front-end, almost immediately. This can in turn redirect us directly to that URL. The result is that we are logged into the site without having to wait for a fully logged Operation to run.
In the same way that Operations are made up of Tasks via inline entities, other entities such as Sites and Platforms are themselves made up of Operations embedded as inline entities. When we create a Platform entity, we instantiate all of its Operations and related Tasks. Among other things, this allows us to reuse Tasks between Operations.
For example, when, taking a backup, we will want to record the file path to the tarball. This data then becomes available to the restore task that may come later.
This case also illustrates the need for the back-end to be able to write data to the front-end. This is another function of relayd in the queue architecture. (see the upcoming post on this for more details). In addition to writing logs to Operation entities, it can write data to any field within any entity on the front-end.
The sequence diagram below illustrates the flow from an Operation being triggered to run, through placing a task on the queue, running the backend executor (currently Ansible, soon Kubernetes), and getting feedback returned to the frontend.
This architecture largely mirrors how Aegir 3 works. However, it provides a more flexible, robust and scalable solution. In our next post, we’ll take a look at the higher-level UI architecture we plan to implement to represent the key components in our Kubernetes hosting framework: Clusters, Projects, Releases, and Environments.
</content:encoded>
    </item>
    
    <item>
      <title>Kubernetes backend for Aegir5</title>
      <link>https://consensus.enterprises/blog/aegir5-kubernetes/</link>
      <pubDate>Mon, 20 Mar 2023 09:00:01 -0500</pubDate>
      
      
      <guid isPermaLink="false">Kubernetes backend for Aegir5 on Consensus Enterprises Blog published Mon, 20 Mar 2023 09:00:01 -0500</guid>
      
      <description> Lately we’ve been working with clients ranging from large Canadian government departments to small commercial SaaS companies, who have asked us to deploy CMS apps to Kubernetes (K8S) clusters running on Openstack. In spite of our continued feeling that most of the time Kubernetes Won’t Save You, we’ve found it to be surprisingly useful in certain contexts. In fact, we’ve started to think that K8S will prove an extremely valuable backend to plug in to our existing Aegir5 front-end and queue …</description>
      <content:encoded> Lately we’ve been working with clients ranging from large Canadian government departments to small commercial SaaS companies, who have asked us to deploy CMS apps to Kubernetes (K8S) clusters running on Openstack. In spite of our continued feeling that most of the time Kubernetes Won’t Save You, we’ve found it to be surprisingly useful in certain contexts. In fact, we’ve started to think that K8S will prove an extremely valuable backend to plug in to our existing Aegir5 front-end and queue system.
We started developing this system for a project that required a Django app paired with a React frontend. This presented an opportunity to prototype a system capable of hosting a fairly complex application. Since then, we have deployed multiple Drupal sites in a similar fashion. This transition was surprisingly straight-forward; partly due to not needing to support headless scenarios, and thus being able to simplify quite a bit.
As shown in the diagram below, traffic enters the system via the router that directs traffic to the cluster. The router exposes a public IP address, to which we point our DNS entries. From there the K8S ingress service directs traffic within the cluster.
In addition, the ingress controller automatically generates Let’s Encrypt HTTPS certificates, and acts as the HTTPS endpoint, handling the TLS handshake, etc.
Traffic gets directed to the Drupal deployment, which in turn, connects to the database deployment. These are running Docker containers. In addition, temporary job containers can be launched to perform specific tasks, such as installing the site, or running cron.
In the case of the Drupal containers, we’re running a custom Drupal image that bakes our code base in. The database deployment, for its part, is using a stock mariadb image.
Our custom Drupal image, by including the project code base, provides us with reproducible builds. We can deploy this same image to multiple environments with confidence that it will be consistent across all of them.
Both the database, and the Drupal site are connected to storage via Persistent Volume Claims (PVCs). More on this later.
We use Terraform to deploy the clusters themselves to OpenStack service providers. With Terraform, we can define the size of the Kubernetes clusters that we want to run and launch them programmatically.
Because the initial application was intended to be a SaaS product, we ended up engineering a multi-cluster multi-environment architecture. For this project, we had a development cluster and a production cluster. We have since renamed them “unstable” and “stable” respectively, to indicate which types of environments are appropriate to host on each.
Our client was targeting their products at large financial institutions. As such, we were anticipating fairly stringent security requirements. Each financial institution wants their client data isolated from any other users of the system. By supporting multiple clusters and multiple environments per cluster, we provided a multi-tenant system that could isolate data at a number of different levels.
While that capability is certainly interesting, we have primarily been implementing and using simpler development workflows. In our Drupal projects, we have primarily used a single cluster with testing, staging and production environments. These environments all run within a single Kubernetes cluster. However, they isolate resources effectively by using K8S namespaces.
Once we have a cluster running, most of the workflows happen within K8S. We keep these logically segmented using namespaces. Together with dedicated storage, namespaces define environments. Within these environments, we deploy the configuration for the Drupal app itself.
In designing this architecture, we also wanted to take into account persistent data. In both the Django and the Drupal scenarios, we had data being stored in a database and files that were uploaded into the application and stored on the filesystem.
In order for this to persist between rebuilds of the application itself, we extended our concept of an environment to include not only the name space, but also the Persistent Volume Claims (PVCs), where we were storing this data. These are all defined as Kubernetes resources, but are handled separately, so as not to never mistakenly delete files or data.
This architecture basically comes down to generating various configuration files and instantiating the resources that they describe. We have wrapped these in Drumkit (GNU Make) targets that template the configuration files (using Mustache), and run all necessary commands in the correct order, with the appropriate options and arguments.
This mirrors the functionality of Provision in Aegir. Our intention is to use this system as a backend for Aegir5. Watch for an upcoming blog post which tackles our planning and vision for next steps!
</content:encoded>
    </item>
    
    <item>
      <title>Aegir5 Development is Happening!</title>
      <link>https://consensus.enterprises/blog/aegir5-is-happening/</link>
      <pubDate>Sat, 25 Feb 2023 09:00:00 -0500</pubDate>
      
      
      <guid isPermaLink="false">Aegir5 Development is Happening! on Consensus Enterprises Blog published Sat, 25 Feb 2023 09:00:00 -0500</guid>
      
      <description>Aegir5 development is happening! We (Consensus) have been making steady progress on it over the last few years and are looking to kick off a new burst of focused development. Here’s a summary of progress that has been made so far and how you can contribute.
First off, as you’re probably aware, Aegir5 is a complete re-write of Aegir. We are intending to build on all the great aspects of Aegir, while freeing ourselves from a codebase that is rooted in PHP 4. We’re using D9+ alongside modern …</description>
      <content:encoded>Aegir5 development is happening! We (Consensus) have been making steady progress on it over the last few years and are looking to kick off a new burst of focused development. Here’s a summary of progress that has been made so far and how you can contribute.
First off, as you’re probably aware, Aegir5 is a complete re-write of Aegir. We are intending to build on all the great aspects of Aegir, while freeing ourselves from a codebase that is rooted in PHP 4. We’re using D9&#43; alongside modern middleware and back-end components.
The front-end (Drupal) and the queue system (based on Celery) are working fairly well. We’ve mostly reproduced the Aegir 3 behaviour, and it has a similar look and feel. This is the most recent work that’s been done directly in the Aegir5 repo, and dates back about a year, or more. (See for example aegir#94.) It’s suffering from some bitrot, so we’ll need to do a bit of cleanup.
Bear in mind that we’re self-funding this project, so we aren’t currently able to dedicate much time and budget to it directly. However, we have had a number of contracts, both current and in the recent past, where we’ve been able to evolve some of the middleware and back-end components.
For example, we recently worked with the Drupal Association to build Rugged, a TUF server implementation to secure the Drupal Composer repository. The Drupal Infrastructure team is in the process of beta testing this functionality on drupal.org, and is very much in line with the Aegir project’s goals of making updates easy and secure.
More directly related to Aegir5, Rugged uses Celery extensively, and started out building from the components we’re using in Aegir5. We’ve developed them much further within the context of that project, and plan to port those improvements back to Aegir5.
Likewise, our initial plan was to build the Aegir5 back-end using Ansible. While we have some basic playbook elements in Aegir5 currently, we’ve had a number of clients recently ask us to build fully automated Kubernetes-based hosting systems. Our first prototype is hosting a Django/React app, and is working well in production.
We’ve been hosting our Kubernetes clusters on OpenStack, since we’ve been striving for a fully FLOSS stack as part of our overall goals for Aegir5. However, a number of our larger institutional clients are restricted to using one of the major cloud vendors. So we’ve been architecting our automation to support any Kubernetes cluster.
We’re currently refining these components for a Drupal upgrade project for a department of the Government of Canada. The Drupal-on-Kubernetes piece was mostly completed a couple weeks ago. We’re continuing to enhance and stabilize it. Next, we’re planning to integrate something along those lines as the default back-end for Aegir5.
We do not have a timeline for the integration of these components into Aegir5, mostly due to the aforementioned time/budget constraints. However, we are eager to proceed with that work.
We have had a handful of organizations express interest in possibly funding some of this upcoming work, some of whom are currently hosting several hundred Drupal sites each on Aegir 3.
If you know of someone who might be interested in helping to fund this work, please let us know.
We’re undertaking to update the Aegir5 roadmap to reflect the progress we’ve made, and to outline next steps. Ideally we’ll be able to get a detailed enough break-down to be able to broadly estimate remaining effort for an alpha release.
Hopefully this gives a good picture of the current state of Aegir5 development. We’ll be publishing some subsequent posts in the coming days to describe in more detail our Drupal-on-Kubernetes architecture, as well as how we aim to integrate the existing frontend and queue system work to achieve an MVP Aegir5.
If you have any questions, don’t hesitate to ask. Aside from our Contact form, you can find us on LinkedIn or Matrix, and always eager to talk about Aegir!
</content:encoded>
    </item>
    
    <item>
      <title>Moving Terraform State from OpenStack Swift to GitLab</title>
      <link>https://consensus.enterprises/blog/moving-terraform-state-from-openstack-swift-to-gitlab/</link>
      <pubDate>Mon, 09 Jan 2023 09:00:00 -0400</pubDate>
      
      
      <guid isPermaLink="false">Moving Terraform State from OpenStack Swift to GitLab on Consensus Enterprises Blog published Mon, 09 Jan 2023 09:00:00 -0400</guid>
      
      <description>For our cloud computing, we typically use an OpenStack provider because of its open-source nature: There’s no vendor lock-in, and the IaaS code is peer-reviewed unlike providers such as AWS, Azure, GCP, etc. (Shout out to Vexxhost for having great support!) As such, we’ve been using OpenStack’s Swift object storage service for storing Terraform’s state, which allows Terraform to track all of the resources it manages for automating infrastructure.
Recently, however, support for the Swift backend …</description>
      <content:encoded>For our cloud computing, we typically use an OpenStack provider because of its open-source nature: There’s no vendor lock-in, and the IaaS code is peer-reviewed unlike providers such as AWS, Azure, GCP, etc. (Shout out to Vexxhost for having great support!) As such, we’ve been using OpenStack’s Swift object storage service for storing Terraform’s state, which allows Terraform to track all of the resources it manages for automating infrastructure.
Recently, however, support for the Swift backend has been removed. If you’re still using Swift for this purpose, you’ll need to migrate your Terraform state files to another backend. Because the official migration documentation is sparse, I’ll describe how to migrate from Swift to GitLab-managed Terraform state. GitLab is a fantastic option because it can be used to manage so many other aspects of your project that you need anyway: Git repository hosting, issue tracking, CI/CD, etc. We use GitLab for all of our projects so it’s a great fit for us.
The actual step of migrating the data is well supported, but there’s some required set-up before and after.
 When you change backends, Terraform gives you the option to migrate your state to the new backend. This lets you adopt backends without losing any existing state.
  Downgrade to the latest pre-1.3 Terraform version.  e.g. sudo apt install terraform=1.2.9   Navigate to your Terraform directory.  cd /path/to/git/repository/terraform   Move your local state files out of the way as they could be set up for a different environment.  mv .terraform /tmp   Set up your environment variables to connect to use your existing state backend.  e.g. source ../openstackrc/vexxhost-...-staging-ca-ymq-1.openrc.sh   Initialize Terraform from the remote state.  terraform init   Back up your current state.  cp .terraform/terraform.tfstate terraform.tfstate.backup-staging   In your Terraform code, in your backend stanza, replace swift with http. Unset the old state environment variables.  export TF_CLI_ARGS_init=   Fetch one of your Gitlab personal access tokens with the api permission. If you don’t have any that aren’t expired, create a new one in your settings.  To actually migrate the data, the GitLab documentation says to set a single environment variable, and then manually run terraform init with many options. Given that this is error-prone and not easily repeatable, I’d recommend using a shell script (or similar) instead.
Create a file named setup-terraform-variables, and populate it like so:
#!/usr/bin/env bash ############################################################################# ## Set up Terraform variables. ############################################################################# # Set up the Gitlab.com state backend. export OS_PROJECT_CLOUD=&#34;$OS_PROJECT_DESCRIPTION-$OS_PROJECT_ENVIRONMENT-$OS_REGION_NAME&#34; export TF_GITLAB_PROJECT_ID=&#34;&#34; echo &#34;Please enter your gitlab.com username: &#34; read -r TF_GITLAB_USERNAME export TF_GITLAB_USERNAME echo &#34;Please enter your gitlab.com personal access token: &#34; read -sr TF_GITLAB_PASSWORD export TF_GITLAB_PASSWORD export TF_STATE_ADDRESS=&#34;https://gitlab.com/api/v4/projects/${TF_GITLAB_PROJECT_ID}/terraform/state/${OS_PROJECT_CLOUD}&#34; export TF_CLI_ARGS_init=&#34;\ -backend-config=&#39;address=$TF_STATE_ADDRESS&#39; \ -backend-config=&#39;lock_address=$TF_STATE_ADDRESS/lock&#39; \ -backend-config=&#39;unlock_address=$TF_STATE_ADDRESS/lock&#39; \ -backend-config=&#39;username=$TF_GITLAB_USERNAME&#39; \ -backend-config=&#39;password=$TF_GITLAB_PASSWORD&#39; \ -backend-config=&#39;lock_method=POST&#39; \ -backend-config=&#39;unlock_method=DELETE&#39; \ -backend-config=&#39;retry_wait_min=5&#39;&#34; You can set other Terraform variables in here as well, and include it in other deployment-environment-specific shell scripts that you run to set up each one. For example, if you’re using OpenStack generally, these would be your openstackrc files, which contain your credentials for accessing the API.
For a further optimization, you can write the GitLab credentials to a local file so as not to have to enter them every time, but I’ll leave this as an exercise to the reader. (If I get a chance, I’ll come back here and update it.)
In your Terraform configuration files, it’s necessary to change the backend type from Swift to HTTP.
terraform { - backend &#34;swift&#34; { &#43; backend &#34;http&#34; {  # Must be read from environment variable `TF_CLI_ARGS_init` because normal # variables cannot be used here. } } If you’re wondering why we need to use TF_CLI_ARGS_init, and can’t use Terraform variables in the stanza, see my earlier article Setting Deployment Environments’ Terraform State Backends with Environment Variables .
You can now run:
 terraform init  You should now see something like this, which requires your confirmation part-way through.
Initializing the backend... Terraform detected that the backend type changed from &#34;swift&#34; to &#34;http&#34;. Acquiring state lock. This may take a few moments... Acquiring state lock. This may take a few moments... Do you want to copy existing state to the new backend? Pre-existing state was found while migrating the previous &#34;swift&#34; backend to the newly configured &#34;http&#34; backend. No existing state was found in the newly configured &#34;http&#34; backend. Do you want to copy this state to the new &#34;http&#34; backend? Enter &#34;yes&#34; to copy and &#34;no&#34; to start with an empty state. Enter a value: yes Releasing state lock. This may take a few moments... Successfully configured the backend &#34;http&#34;! Terraform will automatically use this backend unless the backend configuration changes. Initializing provider plugins... [...] Terraform has been successfully initialized! You may now begin working with Terraform. Try running &#34;terraform plan&#34; to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.  This will purge your old state, and set it up to match the new remote state.
 Move your local state files out of the way as they reflect the old state backend.  mv .terraform /tmp   Upgrade Terraform to the latest version.  e.g. sudo apt install terraform   Set up your environment variables again, using the updated code, to connect to your desired cloud environment. This script must include setup-terraform-variables as discussed above.  source ../openstackrc/vexxhost-...-staging-ca-ymq-1.openrc.sh   Initialize Terraform from the remote state.  terraform init    You can now see any of your state files in the GitLab Web UI on your Gitlab project’s page. Simply navigate to Infrastructure - Terraform, and they’ll be listed.
</content:encoded>
    </item>
    
    <item>
      <title>Setting Deployment Environments&#39; Terraform State Backends with Environment Variables</title>
      <link>https://consensus.enterprises/blog/setting-environments-terraform-state-backends-with-environment-variables/</link>
      <pubDate>Mon, 12 Dec 2022 14:00:00 -0400</pubDate>
      
      
      <guid isPermaLink="false">Setting Deployment Environments&#39; Terraform State Backends with Environment Variables on Consensus Enterprises Blog published Mon, 12 Dec 2022 14:00:00 -0400</guid>
      
      <description>Terraform is an essential tool for automating cloud-computing infrastructure and storing it in code (IaC). While there are several ways to navigate between deployment environments (e.g. Dev, Staging &amp; Prod), I’d like to talk about how this can be done with environment variables, and explain why it can’t be done more naturally with Terraform variables.
I originally wrote this as a comment on the feature request Using variables in terraform backend config block, which explains Terraform’s design …</description>
      <content:encoded>Terraform is an essential tool for automating cloud-computing infrastructure and storing it in code (IaC). While there are several ways to navigate between deployment environments (e.g. Dev, Staging &amp; Prod), I’d like to talk about how this can be done with environment variables, and explain why it can’t be done more naturally with Terraform variables.
I originally wrote this as a comment on the feature request Using variables in terraform backend config block, which explains Terraform’s design limitations preventing it from allowing any variables in backend configurations, which is what Terraform uses to determine where to store its state data files (which track the cloud resources it manages).
To illustrate, this is where variables can’t be used, even though the configuration must change when the environment changes:
terraform { backend &#34;whatever&#34; { [...] } }  Alternatively, it’s possible to have a single backend state configuration that stores data for multiple environments using Workspaces. You can then use Terraform CLI commands to switch between them. However, this solution is not not appropriate for all use cases, as per the documentation:
 Workspaces are not appropriate for system decomposition or deployments requiring separate credentials and access controls.
 If this isn’t a problem for you, Workspaces is a good option. Otherwise, please keep reading.
In demonstrating a solution, I’m going to be working with OpenStack, which is the IaaS run by many cloud providers, but the same concept can be applied to other IaaS, such as AWS, Azure, GCP, etc. Here, the backend state data will be stored in OpenStack’s Swift object storage service.
Update (2023-04-11): While the example below is still valid conceptually, Swift can no longer be used as a Terraform backend because support for it has been removed. If you’re still using Swift for this purpose, the official migration documentation is sparse. However, I provide guidance in a more recent article: Moving Terraform State from OpenStack Swift to GitLab.
Typically, you’d download an OpenStack RC file, which contains the credentials needed to access the API. In each of these (e.g. vexxhost-abc-prod-ca.openrc.sh, where the format is provider-project-environment-region), I append the following lines to the end:
[...] ############################################################################# ## Additional set-up not included with IaaS provider&#39;s OpenStack RC files ### ############################################################################# export OS_PROJECT_ENVIRONMENT=&#34;abc-prod-ca&#34; source $(dirname &#34;$0&#34;)/setup-terraform-variables.sh The sourced (included) file then looks like:
#!/usr/bin/env bash ############################################################################# ## Set up Terraform variables. ############################################################################# # Set up backend state container names. export OS_PROJECT_STATE=&#34;$OS_PROJECT_ENVIRONMENT-terraform-state&#34; export OS_PROJECT_STATE_ARCHIVE=&#34;$OS_PROJECT_STATE-archive&#34; export TF_CLI_ARGS_init=&#34;\ -backend-config=&#39;container=$OS_PROJECT_STATE&#39; \ -backend-config=&#39;archive_container=$OS_PROJECT_STATE_ARCHIVE&#39;&#34; # You can set other TF variables in here as well. echo &#34;Please enter the outgoing e-mail account&#39;s password: &#34; read -sr TF_VAR_smtp_password_unquoted export TF_VAR_smtp_password=&#34;\&#34;$TF_VAR_smtp_password_unquoted\&#34;&#34; The special environment variable here is TF_CLI_ARGS_init. This is what Terraform uses to configure the backend, if it’s set. So by changing that environment variable, you can change the backend configuration. All that’s needed in the code is the following, basically just the backend type, with details being pulled in from the environment.
In main.tf (or wherever), the backend definition:
terraform { backend &#34;swift&#34; {# Must be read from environment variable `TF_CLI_ARGS_init` because normal # variables cannot be used here.  } }  To switch between environments, I simply source another OpenStack RC file; I have one for every environment that I care about. With the above set-up, it also switches the Swift object storage containers used for backend state. You can then run terraform init.
I’ve found that sometimes it’s necessary to delete your .terraform directory before rerunning terraform init though, or it’ll get confused and you’ll get strange error messages. So as standard practise, I run the following command to remove it first:
mv .terraform /tmp   You cannot use Terraform variables to vary the backend state configuration. You can, however, use the environment variable TF_CLI_ARGS_init instead. Run a script to set this environment variable with the configuration matching the deployment environment you’d like to work with. Simply specify the backend type in the Terraform code, and TF_CLI_ARGS_init along with your script(s) will take care of the rest.  </content:encoded>
    </item>
    
    <item>
      <title>Protecting your cloud networks with WireGuard VPN and Ansible</title>
      <link>https://consensus.enterprises/blog/protecting-cloud-networks-wireguard-ansible/</link>
      <pubDate>Fri, 24 Jul 2020 11:02:26 -0400</pubDate>
      
      
      <guid isPermaLink="false">Protecting your cloud networks with WireGuard VPN and Ansible on Consensus Enterprises Blog published Fri, 24 Jul 2020 11:02:26 -0400</guid>
      
      <description> Within cloud computing, there are various types of sites and services not meant for public consumption (e.g. analytics software, databases, log servers, etc.). For security reasons, it’s best to keep these accesssible only via the private network, which is behind the firewall.
To provide access to these resources, a virtual private network (VPN) should be used, with network access granted only to trusted individuals within the organization.
Traditionally, OpenVPN, IPsec and other solutions were …</description>
      <content:encoded> Within cloud computing, there are various types of sites and services not meant for public consumption (e.g. analytics software, databases, log servers, etc.). For security reasons, it’s best to keep these accesssible only via the private network, which is behind the firewall.
To provide access to these resources, a virtual private network (VPN) should be used, with network access granted only to trusted individuals within the organization.
Traditionally, OpenVPN, IPsec and other solutions were the go-to options within the open-source software space. However, these are often complex to set up and have relatively massive code bases making them difficult to maintain.
For example, OpenVPN requires that a certificate authority (CA) be set-up. This is a complex piece of software, which shouldn’t be necessary for running a VPN. WireGuard simply requires the exchange of public keys in order to set up a secure connection, much like SSH and PGP.
There’s been a lot of interest in WireGuard lately, notably because:
 It was recently added to the Linux kernel. NordVPN, one of the major VPN service providers, has started using it. Mozilla, the company behind the Firefox Web browser, just started offering it as a service. It’s recommended in The Definitive 2019 Guide to Cryptographic Key Sizes and Algorithm Recommendations  However, in the Why Not WireGuard article, some opposition was raised. Let’s tackle some of the points raised there.
Fine, but we’re doing the opposite. The clients can have dynamic IP addresses, but the server never will. So it’s irrelevant for this use case.
That’s precisely the purpose of this article: To introduce an easy way to set it up and maintain it with Ansible.
Lacking cipher agility is actually a good thing. A better approach is to use versioned protocols. And it’s actually no more difficult to upgrade WireGuard clients than anything else. Both of these non-issues are discussed very nicely in the article Against Cipher Agility in Cryptography Protocols.
As it was recently added to the Linux kernel, this is no longer an issue.
While performance can always be improved, this doesn’t appear to be a critical issue for the application. For most use cases, it’s perfectly usable.
None of the above “issues” are actually a problem here.
Ansible allows for automated deployment of configuration, which removes the need for manually installing, configuring and maintaining applications. It provides tonnes of modules, including those for files, storage, system, networking and even cloud provisioning (although I would generally recommend Terraform for this purpose).
Its units of work are called “tasks” that are run sequentially (procedural) in “roles” and “playbooks” to perform operations such as installing server software, its configuration, and handling various other types of system administration. Ansible strives for simplicity, resulting in playbooks that are essentially self-documenting. It can safely be run multiple times (as it strives to be idempotent), running tasks only when necessary, leaving already-configured items as-is.
While there were several WireGuard roles available for installing and maintaining the application, they either:
 didn’t cater to the cloud gateway VPN use case, lacked documentation, and/or intentionally omitted critical elements (e.g. packet forwarding to internal hosts) for implementation by the user.  As such, I’ve written a comprehensive one.
It’s packaged as a collection as this is the newer distribution format that doesn’t concern itself with the location of source control repositories. Traditionally, it was necessary for roles to be hosted on GitHub for them to be published on Galaxy, the site for sharing Ansible contributions. As I prefer GitLab for hosting code repositories, this seemed more natural. The project is therefore hosted on GitLab.com.
The collection contains the single WireGuard role, and can be installed with ansible-galaxy (Ansible 2.9&#43;). For older versions of Ansible, simply clone the Git repository and create a symbolic link to roles/wireguard_cloud_gateway within it.
Documentation can be found in the role’s README.
Some of the other roles I researched didn’t provide much support for configuring the client side of the VPN, meaning the devices which connect to the cloud gateway server to access private network resources.
My role, on the other hand, can be run in either client or server mode: the same role can be used for configuring both. Running it in server mode configures the server (on the gateway VM), and running it in client mode configures the client devices (who connect to the server to gain access to the private network).
For cloud security akin to traditional firewalls, security groups are essential for protecting virtual-machine (VM) compute instances. While these can be configured manually, ideally such configuration would be infrastructure as code (IaC) implemented via a tool such as Terraform, stored in a version control system (VCS) such as Git.
In a typical VPN-server set-up, the incoming (“ingress”) rules for such a “VPN” security group would block access to all ports except the one upon which the VPN communicates. This configuration should be applied to the VM that will be running WireGuard. However, if this is the case, using Ansible to install it won’t work because Ansible uses SSH to connect to the VM, and the SSH port is blocked.
In order to allow for such a secure set-up, a security group ID (e.g. “public_ssh”) can be provided to the role as a variable, which will be used to temporarily allow SSH access. Once the installation is complete, this temporary access will be revoked.
For those of us that rely on VPN technology, it’s often necessary to connect to multiple VPNs at the same time, or at least prevent network resource IDs from overlapping. For example, you want to avoid having two VMs on different networks from having the same IP address.
WireGuard supports this by allowing multiple interfaces. By default, wg0 is used as the first one, but wg1, wg2, etc. can all coexist. If each remote network can exist on a different subnet, there’s no conflict from the client perspective. For example:
 wg0 can be used to access network A, with subnet 10.1.0.0/16 wg1 can be used to access network B, with subnet 10.2.0.0/16  To set this up in your Ansible playbook when calling the role, set the service_interface variable. By default, it’s wg0. Also, be sure to set the client_accessible_ips properly; this defines the subnet. For details, see the default variables file.
The role was originally written for specific systems, notably OpenStack networks and Ubuntu VMs. However, we’d like to see the role support as many systems as possible (e.g. the IaaS platforms Amazon Web Services (AWS), Microsoft’s Azure, Google Cloud Platform (GCP), Digital Ocean, etc. and non-Debian-based operating systems (OSes) such as CentOS, Red Hat, etc.).
If you work with these systems, we’re more than happy to accept your supporting code via merge requests. Otherwise, if you’re able to provide funding, we can add support for these systems on your behalf.
To get in touch with us for that, or for any other reason, please use our contact form. We provide consulting in several areas, such as:
 Enterprise cloud architecture Cloud computing infrastructures as a service (IaaS) Infrastructure automation with Terraform Automating full-stack configuration with Ansible OpenStack, Amazon Web Services (AWS), Google Cloud Platform (GCP) &amp; Microsoft Azure consulting Virtual private networking (VPNs) with OpenVPN and WireGuard  </content:encoded>
    </item>
    
    <item>
      <title>Installing the OpenStack CLI on Ubuntu 19.10 (Eoan), 20.04 (Focal) or later</title>
      <link>https://consensus.enterprises/blog/install-openstack-cli-ubuntu-1910/</link>
      <pubDate>Mon, 09 Mar 2020 18:32:00 -0500</pubDate>
      
      
      <guid isPermaLink="false">Installing the OpenStack CLI on Ubuntu 19.10 (Eoan), 20.04 (Focal) or later on Consensus Enterprises Blog published Mon, 09 Mar 2020 18:32:00 -0500</guid>
      
      <description>When working with OpenStack as an infrastructure-as-a-service (IaaS) cloud-computing platform, it’s rather convenient to be able to interface with it via its command-line interface (CLI).
While the service is typically installed on the Ubuntu Long-Term Support (LTS) operating system (OS), which has releases every two years, running the CLI from other OSes, such as interim Ubuntu releases, is often necessary. However, it is currently not possible to install the command-line client with supported …</description>
      <content:encoded>When working with OpenStack as an infrastructure-as-a-service (IaaS) cloud-computing platform, it’s rather convenient to be able to interface with it via its command-line interface (CLI).
While the service is typically installed on the Ubuntu Long-Term Support (LTS) operating system (OS), which has releases every two years, running the CLI from other OSes, such as interim Ubuntu releases, is often necessary. However, it is currently not possible to install the command-line client with supported Debian packages on Ubuntu 19.10.
 Update (2020-05-30): The simplest way to install the OpenStack CLI nowadays, at least on Ubuntu 20.04 (Focal) and later, is via the Snap package. Debian packages are no longer made available:
sudo snap install openstackclients --classic This should be all you need to do; there’s no reason to follow the instructions in the remaining portion of this article.
 Update (2021-08-18): You may run into the following error on Ubuntu 21.04:
% openstack versions show Traceback (most recent call last): File &#34;/usr/local/bin/openstack&#34;, line 5, in  from openstackclient.shell import main ModuleNotFoundError: No module named &#39;openstackclient&#39; If you do, run the following commands:
 sudo apt install pip sudo pip install python_openstackclient  Openstack commands should start working again.
 Attempting to follow the instructions in the documentation for the two listed OpenStack releases, which require an additional software archive, results in the message:
 cloud-archive for Rocky only supported on bionic
  cloud-archive for Stein only supported on bionic
 In addition, attempting to use the native software repository is impossible because the package isn’t available.
As such, I’ve written a short script to fetch and install all of the necessary Debian packages from another release.
#!/bin/sh  DEST_DIR=/tmp/openstack-cli-debs mkdir $DEST_DIR wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-netaddr/python-netaddr_0.7.19-1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-iso8601/python-iso8601_0.1.11-1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/pyinotify/python-pyinotify_0.9.6-1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-monotonic/python-monotonic_1.5-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-oslo.context/python-oslo.context_2.22.1-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-warlock/python-warlock_1.2.0-2_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/s/stevedore/python-stevedore_1.30.1-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-os-service-types/python-os-service-types_1.6.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-oslo.config/python-oslo.config_6.8.1-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-debtcollector/python-debtcollector_1.20.0-2_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-oslo.log/python-oslo.log_3.42.3-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-os-client-config/python-os-client-config_1.31.2-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-requestsexceptions/python-requestsexceptions_1.4.0-1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-deprecation/python-deprecation_2.0.6-1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-dogpile.cache/python-dogpile.cache_0.6.2-6_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-json-patch/python-jsonpatch_1.21-1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-munch/python-munch_2.3.2-1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-openstackclient/python-openstackclient_3.18.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-cinderclient/python-cinderclient_4.1.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-cliff/python-cliff_2.14.1-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-glanceclient/python-glanceclient_2.16.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-keystoneauth1/python-keystoneauth1_3.13.1-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-keystoneclient/python-keystoneclient_3.19.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-neutronclient/python-neutronclient_6.11.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-novaclient/python-novaclient_13.0.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-openstacksdk/python-openstacksdk_0.26.0-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/universe/p/python-osc-lib/python-osc-lib_1.12.1-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-oslo.i18n/python-oslo.i18n_3.23.1-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-oslo.serialization/python-oslo.serialization_2.28.2-0ubuntu1_all.deb wget -cP $DEST_DIR http://mirrors.kernel.org/ubuntu/pool/main/p/python-oslo.utils/python-oslo.utils_3.40.3-0ubuntu1_all.deb sudo dpkg -i $DEST_DIR/* sudo apt --fix-broken install Hopefully this helps other folks who have also run into this issue.
</content:encoded>
    </item>
    
    <item>
      <title>Drupal North 2019: Drupal SaaS: Building software as a service on Drupal</title>
      <link>https://consensus.enterprises/blog/drupal-saas-building-software-as-a-service-on-drupal/</link>
      <pubDate>Fri, 15 Nov 2019 15:35:00 -0500</pubDate>
      
      
      <guid isPermaLink="false">Drupal North 2019: Drupal SaaS: Building software as a service on Drupal on Consensus Enterprises Blog published Fri, 15 Nov 2019 15:35:00 -0500</guid>
      
      <description>On Friday, June 14th, I presented this session at Drupal North 2019. That’s the annual gathering of the Drupal community in Ontario and Quebec, in Canada.
As I realized I hadn’t yet posted this information yet, I’m doing so now.
Session information:
 Are you (considering) building a SaaS product on Drupal or running a Drupal hosting company? Have you done it already? Come share your experiences and learn from others.
Among other things, we’ll be discussing:
 Project vs. product business …</description>
      <content:encoded>On Friday, June 14th, I presented this session at Drupal North 2019. That’s the annual gathering of the Drupal community in Ontario and Quebec, in Canada.
As I realized I hadn’t yet posted this information yet, I’m doing so now.
Session information:
 Are you (considering) building a SaaS product on Drupal or running a Drupal hosting company? Have you done it already? Come share your experiences and learn from others.
Among other things, we’ll be discussing:
 Project vs. product business Installation profiles / distributions Customer service (e.g. GitLab’s Service Desk) Hosting architecture (Drupal hosting companies vs. Aegir) Infrastructure (IaaS hosting providers: OpenStack vs. AWS, GCS, Azure, etc.) E-commerce, recurring billing and subscription provider integration  Aegir Site Subscriptions Others?   Resource quotas Site admin access permissions for clients  …and any other related topics that come up.
 A video recording of my presentation is available on:
 Drupal.tv YouTube  My slides (with clickable links) are available on our presentations site.
</content:encoded>
    </item>
    
    <item>
      <title>DrupalCamp Ottawa 2019: Automate All the Things</title>
      <link>https://consensus.enterprises/blog/drupalcamp-ottawa-2019-automate-all-the-things/</link>
      <pubDate>Thu, 24 Oct 2019 22:55:00 -0400</pubDate>
      
      
      <guid isPermaLink="false">DrupalCamp Ottawa 2019: Automate All the Things on Consensus Enterprises Blog published Thu, 24 Oct 2019 22:55:00 -0400</guid>
      
      <description>On Friday, October 18th, I presented at DrupalCamp Ottawa 2019. That’s the annual gathering of the Drupal community in Ottawa, Ontario, Canada.
Session information:
 Ever heard of infrastructure-as-code? The idea is basically to use tools like Ansible or Terraform to manage the composition and operation of your cloud systems. This allows infrastructure to be treated just like any other software system. The code can be committed into Git which allows auditability, and reproducibility. It can …</description>
      <content:encoded>On Friday, October 18th, I presented at DrupalCamp Ottawa 2019. That’s the annual gathering of the Drupal community in Ottawa, Ontario, Canada.
Session information:
 Ever heard of infrastructure-as-code? The idea is basically to use tools like Ansible or Terraform to manage the composition and operation of your cloud systems. This allows infrastructure to be treated just like any other software system. The code can be committed into Git which allows auditability, and reproducibility. It can therefore be tested and integrated into full continuous delivery processes.
Ansible provides tonnes of cloud management modules, from simple Linodes or Digital Ocean Droplets through globe-spanning AWS networks. Ansible also strives for simplicity, resulting in playbooks that are essentially self-documenting.
In this session, we will:
 explore the principles of infrastructure-as-code and how to operationalize them; introduce Ansible and it’s cloud modules; build a full OpenStack cloud infrastructure end-to-end from scratch.   A video recording of my presentation is available on YouTube.   My presentation slidedeck can be downloaded here: Automate All the Things!
</content:encoded>
    </item>
    
  </channel>
</rss>
