Balancing Existing and Extensible: Integrating Windows into a Linux Development Platform
By Chris Terry, Platform Engineer
Creating custom integration solutions is often a balancing act. Given a set of constraints and existing infrastructure, you may not want to reinvent the wheel. Nor do you want to quickly create a solution that doesn’t have the flexibility to extend over the long haul.
At Kenzan, one of our clients wanted the flexibility to deploy backend Windows tooling. Like many progressive software shops, our client had a pure Linux infrastructure. By default, they deployed apps and tools using Linux-based AMIs on the AWS cloud. Yet they were also constantly on the lookout for new tools and techniques to maintain their competitive edge. At times they had observed Windows tools that might actually work well as backend services, but the internal R&D time was deemed too costly to pursue Windows-based tools or build a strategy around deploying them. This effectively ruled out solutions before their full benefits could be considered. They wanted the flexibility to choose software based on merit and to think outside the Linux bubble.
Extending a Firm Foundation
Kenzan had previously been brought in to help the client migrate data center apps to cloud-based AMIs, as well as build out full CI/CD capabilities. We leveraged tools like Jenkins, Ansible, and Packer to manage and build AMI images, with images organized in the typical one-service-per-role fashion. We also utilized Terraform for network and security infrastructure, and Spinnaker to smoothly deploy projects into development and production environments.
When we were tasked with finding an integration point for Windows, we considered potential solutions from two primary angles: development and operations. We weighed the tools, languages and formats already in use, factoring any new items into budgeted staff training and handoff time. We had to consider Windows security and authentication, both within AWS cloud and the client’s existing internal authentication infrastructure. Additionally, we had to consider the interaction options. For example, end-to-end Microsoft-native remote connectivity could be seamless, but would add developer constraints and administrative overhead.
We started by investigating options for automating Windows image building and instance deployment using the existing AMI packaging tools. Ansible was an obvious choice given our use of it for provisioning Linux AMIs, however, its Windows-native compatibility had limitations that didn’t fit the existing infrastructure patterns in place. One workaround would have required installing Cygwin and several support packages, but this created a dependency management situation that would not have been sustainable. SaltStack and Chef were also considered, but both would have cluttered our infrastructure toolchain and repositories, and also required developers to learn additional languages and patterns.
We eventually settled on creating a custom “Ansible-like” provisioner for building Windows AMIs, primarily using Packer’s Powershell capabilities. We were even able to mimic role-based installs by having Powershell take JSON “role” files and recursively install dependent roles and then finally a base roll.
This enabled us to leverage OS-native tools as well as the client’s existing development patterns and skills. The provisioner was built with extensibility in mind for future adjustments. This mitigated potential scope creep and made developer training and long-term codebase management significantly easier.
Additionally, we had to consider how the client’s developers and administrators would interact with these systems. They were already monitoring their infrastructure with SignalFX. SignalFX provides a native Windows monitoring package, and so we used it as our first Windows instance role. The role install provided a training example to the Client’s development and operations teams.
Developer and administrative remote access to Linux AMI instances was being provided on a per-environment basis via Linux bastion/jump hosts to minimize potential attack surface. An end-to-end Microsoft-native remote access pattern was considered for windows instances, but set aside due to administrative and cost overhead. The native approach would have resulted in deployment of additional services alongside the instances as opposed to using existing resources. Since the client’s expertise is in Linux, that additional infrastructure would have to be trained for or hired for.
The final decision was to use existing Bastion hosts and the cloud provider’s SSH keypair-based access. This reduced proliferation of shared keys. The process for making the API calls to retrieve the Windows Administrator password was automated using standard SSH multiplexing functions, removing the temptation to copy private keys onto the bastion servers while also removing the need to allow API access outside of the bastioned private network.
Balance to Build On
Because we were able to implement this solution within the space of a quarter, Windows-based projects were able to start fresh with the tooling already in place. This reduced the risk of “hand tuned” systems since the foundations already existed, automated, in code. The automation in place kept development turnaround time at a minimum from the start.
The custom-built tools were based on the client’s existing development languages and patterns, so development teams were able to quickly begin building new Windows-based roles alongside existing Linux system roles. Both immediate development and future functionality additions were enabled by a thoughtful, extensible design approach.
Custom integration solutions are often a case study in factoring in time and cost constraints, knowing your audience of existing users, and weighing known technologies against greenfield solutions. Probably the biggest factor in good design is good relationships: because we had a strong collaborative relationship with our clients, we understood what would work for them as an elegant compromise between known and unknown technologies.
Chris is a Platform Engineer at Kenzan. A tinkerer-turned-professional, Chris grew up elbow-deep in his IBM 8088, taking a brief detour as a professional musician before finding his way back into tech as a small business Linux sysadmin. He jumped into the DevOps space designing and managing the infrastructure and automation for a VoIP IVR platform before joining Kenzan in 2016.
At Kenzan, we value the flexibility of innovation, the wisdom of experience, and the feedback from collaboration in equal measure, all in pursuit of the right solution for each problem we help to solve. Email firstname.lastname@example.org for more information about our services and solutions.