Hybrid Automation: Windows and Linux in the Same Polycrate Workspace
Fabian Peter 12 Minuten Lesezeit

Hybrid Automation: Windows and Linux in the Same Polycrate Workspace

Hybrid Infrastructure: Managing Windows and Linux in the Same Polycrate Workspace
Ganze Serie lesen (24 Artikel)

Diese Serie zeigt Schritt für Schritt, wie Ansible mit Polycrate zu einer strukturierten, teilbaren und compliance-fähigen Automatisierungsplattform wird – von den Grundlagen bis zu Enterprise-Szenarien.

  1. Install Polycrate and Build Your First Ansible Block in 15 Minutes
  2. Blocks, Actions, and Workspaces: The Modular Principle of Polycrate
  3. Linux Servers on Autopilot: System Management with Polycrate and Ansible
  4. Nginx and Let's Encrypt as a Reusable Polycrate Block
  5. Managing Docker Stacks on Linux Servers with Polycrate
  6. Many Servers, One Truth: Multi-Server Management with Polycrate Inventories
  7. Windows Automation with Polycrate: Ansible and WinRM Without Pain
  8. Windows Software Deployment without SCCM: Chocolatey and Ansible
  9. Hybrid Automation: Windows and Linux in the Same Polycrate Workspace
  10. Deploy Kubernetes Apps from the PolyHub: From Idea to Deployment in Minutes
  11. Creating Your Own Kubernetes App as a Polycrate Block: A Step-by-Step Guide
  12. Multi-Cluster Kubernetes with Polycrate: Why One Cluster, One Workspace
  13. SSH Sessions and kubectl Debugging: Polycrate as an Operations Tool
  14. Helm Charts as a Polycrate Block: More Control Over Chart Deployments
  15. Policy as Code: Automating Compliance Requirements with Polycrate
  16. Workspace Encryption: Managing Secrets in GDPR Compliance – Without External Tooling
  17. Managing Raspberry Pi and Edge Nodes with Polycrate in IoT and Edge Computing
  18. Enterprise Automation: Building, Versioning, and Sharing Blocks Within Teams
  19. Polycrate MCP: Connecting AI Assistants with Live Infrastructure Context
  20. Polycrate vs. plain Ansible: What You Gain – and Why It's Worth It
  21. The Polycrate Ecosystem: PolyHub, API, MCP, and the Future of Automation
  22. Your First Productive Polycrate Workspace: A Checklist for Getting Started
  23. Auditable Operations: SSH Sessions and CLI Activities with Polycrate API
  24. Polycrate API for Teams: Centralized Monitoring and Remote Triggering

TL;DR

  • Most environments are hybrid: Windows servers for AD, file services, and specialized applications, Linux for web, databases, and automation – separate automation increases complexity and risk.
  • With Polycrate, you create a shared YAML inventory with the groups linux_group and windows_group, encapsulate Linux and Windows playbooks in their own blocks, and manage everything from one workspace.
  • Shared non-sensitive values (e.g. DNS/NTP) go in each block’s config in workspace.polyexplicitly per block (in the hybrid example the same values twice, without YAML anchors). There is no Jinja templating in .poly files.
    Files (SSH keys, kubeconfig, …) live under artifacts/secrets/ and are encrypted with the workspace; sensitive block configuration such as win_admin_password belongs in secrets.poly (not as artifacts/secrets/win_admin_password) – see Workspace encryption.
  • A workflow orchestrates hybrid maintenance: first patch Linux servers, then Windows hosts – all with simple polycrate workflows run … commands, without needing to install Ansible, Python, or pywinrm locally.
  • ayedo supports teams with field-tested hybrid workspaces, workshops, and reference blocks (including PolyHub registry), enabling Windows and Linux admins to work together on a structured, compliance-capable automation basis.

Hybrid Reality: Windows and Linux Belong Together

If you work in a larger company, your world usually looks like this:

  • Active Directory, file servers, many specialized applications: Windows Server
  • Web servers, reverse proxies, databases, monitoring, CI/CD: Linux

In many teams, these worlds end up in separate silos:

  • own Ansible setup for Linux on a Linux admin VM
  • own Ansible setup (or no Ansible at all) for Windows on a separate machine
  • different Python versions, different modules, different standards

Polycrate turns this around: one workspace, two blocks (Linux and Windows), one inventory, one workflow. And everything runs in a container, which takes away the classic dependency problem with Ansible:

  • no local Python or Ansible chaos
  • no extra pywinrm installation for Windows modules
  • reproducible toolchain on every developer or admin machine

In this post, we build just such a hybrid workspace – including inventory, blocks, playbooks, secrets, and workflow.


One Workspace for Everything: workspace.poly with Linux and Windows Block

The workspace is the central hub. Here you define:

  • block instances (Linux and Windows management), including each block’s config
  • optional workspace-wide settings under config in workspace.poly (e.g. container image – see Configuration), not as a free-form bag for arbitrary automation variables
  • a workflow that connects both worlds

There is no template substitution in workspace.poly or block.poly (no Jinja2); values are literal YAML or merged from secrets.poly. See Important limitations.

workspace.poly – set DNS/NTP as literal values in each block’s config (here the same values in linux-mgmt and windows-mgmtno YAML anchors). SSH: Polycrate configures the Ansible environment in the action container (including ANSIBLE_PRIVATE_KEY_FILE) – you do not put ssh_private_key in block config or ansible_ssh_private_key_file in the playbook.

name: acme-corp-automation
organization: acme

blocks:
  - name: linux-mgmt
    from: registry.acme-corp.com/acme/infra/linux-mgmt:0.1.0
    config:
      dns_server: "10.0.0.10"
      ntp_server: "time.acme-corp.com"

  - name: windows-mgmt
    from: registry.acme-corp.com/acme/infra/windows-mgmt:0.1.0
    config:
      dns_server: "10.0.0.10"
      ntp_server: "time.acme-corp.com"
      win_admin_user: "ACME\\ansible-svc"

workflows:
  - name: hybrid-maintenance
    steps:
      - name: update-linux
        block: linux-mgmt
        action: update-linux
      - name: update-windows
        block: windows-mgmt
        action: update-windows

secrets.poly (sensitive block configuration, merged with workspace.poly and overrides on key clash):

blocks:
  - name: windows-mgmt
    config:
      win_admin_password: "…"

The WinRM password is not an artifact path: it lives under blocks[].config in secrets.poly, not as a file artifacts/secrets/win_admin_password. That matches Workspace encryption for secrets.poly (sensitive block configuration) versus files under artifacts/secrets/.

Important:

  • workspace.poly does have a config key, but it is meant for workspace/toolchain settings (e.g. config.image), not for arbitrary global variables such as DNS or inventory parameters – those belong in per-block config (and secrets.poly when sensitive).
  • Merge order (lowest → highest precedence): block.polyworkspace.polysecrets.poly – see Configuration.
  • from: contains the full OCI registry reference including the version tag (like container images); registry.acme-corp.com is an example (not a reference to any specific production registry).
  • Unpacked blocks live under blocks/registry.acme-corp.com/acme/infra/linux-mgmt/ and …/windows-mgmt/ respectively (directory tree mirrors the registry path).
  • Block config merge and inheritance: inheritance and workspaces.
  • The workflow hybrid-maintenance sequentially calls Linux and Windows actions.
    Details: workspaces and workflows.

A Shared Inventory: linux_group and windows_group

Polycrate always uses a YAML inventory in the workspace root under inventory.yml. No INI files, no per-block inventory.

As in the multi-server article, every host appears once under all.hosts; under children you only assign them to groups so Ansible and polycrate ssh share the same canonical host list. Put shared Linux defaults under all.vars; WinRM settings belong on the Windows group because they apply only there.

Our hybrid inventory with two groups:

all:
  vars:
    ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
    ansible_python_interpreter: /usr/bin/python3

  hosts:
    linux01.acme-corp.com:
      ansible_user: ubuntu
    linux02.acme-corp.com:
      ansible_user: ubuntu
    win01.acme-corp.com: {}
    win02.acme-corp.com: {}

  children:
    linux_group:
      hosts:
        linux01.acme-corp.com:
        linux02.acme-corp.com:

    windows_group:
      hosts:
        win01.acme-corp.com:
        win02.acme-corp.com:
      vars:
        ansible_connection: winrm
        ansible_winrm_transport: credssp
        ansible_winrm_server_cert_validation: ignore

A few points about this:

  • Linux hosts: SSH user per host under all.hosts (or as a default in all.vars). Polycrate supplies the private key to Ansible via container environment variables (ANSIBLE_PRIVATE_KEY_FILE, etc.) – no ssh_private_key in workspace.poly and no ansible_ssh_private_key_file in the playbook.
  • Windows hosts: Connection parameters (ansible_connection: winrm etc.) are in the vars of group windows_group.
  • Username and password for WinRM do not go into the inventory but are set in the playbook from encrypted secrets via block.config.win_admin_user and block.config.win_admin_password.

Polycrate automatically sets the environment variable ANSIBLE_INVENTORY when starting the action, so you don’t need to append -i inventory.yml to the Ansible CLI – Polycrate takes care of that for you. More on this in the Ansible integration.


Secrets Done Right: SSH Key and WinRM Password

Hybrid environments also mean hybrid authentication:

  • SSH: Key material lives under artifacts/secrets/ (e.g. id_rsa) and is encrypted with the workspace. For Ansible, Polycrate wires access in the action container via environment (ANSIBLE_PRIVATE_KEY_FILE) – no explicit ssh_private_key in workspace.poly and no ansible_ssh_private_key_file in the playbook.
  • WinRM: The username can live in block config in workspace.poly; put the password in secrets.poly under the matching block (windows-mgmt), not in workspace.poly, so it merges into block.config and is not committed in plain text (or use certificates instead of a password, depending on your setup).

polycrate workspace encrypt encrypts secrets.poly and files under artifacts/secrets/ (see Workspace encryption). You activate and manage this via the CLI, for example:

# Encrypt secrets (e.g., before a Git commit)
polycrate workspace encrypt

# Decrypt for working
polycrate workspace decrypt

In Ansible playbooks (not in .poly files), you use block.config.* – values come from the merged block.poly + workspace.poly + secrets.poly.

This achieves two important things:

  1. Compliance-friendly storage: Secrets are not in plain text in the Git repo – important especially in the context of GDPR (effective since 25.05.2018) and internal security policies.
  2. Good UX/DX: No external vault is needed, no complicated integration. Polycrate brings the workspace encryption feature with age directly (see Workspace encryption).

Linux Block: linux-mgmt with OS-specific Tasks

Let’s start with the Linux part. The block encapsulates everything you want to do for Linux servers – here as an example:

  • package-based update (apt or yum)
  • DNS and NTP basic configuration

In block.poly, name must be the full registry URL – the same string as in from: in workspace.poly, without the version tag (:0.1.0). In short: from: = name + : + tag. That is not the same identifier as the block instance linux-mgmt in workspace.poly. The file lives at blocks/registry.acme-corp.com/acme/infra/linux-mgmt/block.poly (directory tree mirrors the registry path).

# name = from: without tag (full registry path)
name: "registry.acme-corp.com/acme/infra/linux-mgmt"
version: 0.1.0
kind: generic

config:
  dns_server: ""
  ntp_server: ""

actions:
  - name: update-linux
    description: Update Linux servers and set basic configuration
    playbook: linux_update.yml

The associated Ansible playbook blocks/registry.acme-corp.com/acme/infra/linux-mgmt/linux_update.yml:

- name: Update Linux servers and set basic config
  hosts: linux_group
  become: true
  gather_facts: true

  vars:
    dns_server: "{{ block.config.dns_server }}"
    ntp_server: "{{ block.config.ntp_server }}"

  tasks:
    - name: Update package list (Debian family)
      ansible.builtin.apt:
        update_cache: true
      when: ansible_os_family == 'Debian'

    - name: Upgrade packages (Debian family)
      ansible.builtin.apt:
        upgrade: dist
      when: ansible_os_family == 'Debian'

    - name: Upgrade packages (RedHat family)
      ansible.builtin.yum:
        name: "*"
        state: latest
      when: ansible_os_family == 'RedHat'

    - name: Set DNS server in /etc/resolv.conf
      ansible.builtin.lineinfile:
        path: /etc/resolv.conf
        regexp: '^nameserver'
        line: "nameserver {{ dns_server }}"
      when: ansible_os_family in ['Debian', 'RedHat']

    - name: Install NTP package (Debian family)
      ansible.builtin.package:
        name: chrony
        state: present
      when: ansible_os_family == 'Debian'

    - name: Configure NTP server in chrony.conf
      ansible.builtin.lineinfile:
        path: /etc/chrony/chrony.conf
        regexp: '^server'
        line: "server {{ ntp_server }} iburst"
      when: ansible_os_family == 'Debian'

    - name: Restart chrony
      ansible.builtin.service:
        name: chrony
        state: restarted
        enabled: true
      when: ansible_os_family == 'Debian'

Key points:

  • hosts: linux_group – we work on the Linux hosts from the shared inventory, not on localhost.
  • ansible_os_family controls OS-specific tasks (when: conditions). This allows you to handle Debian, RedHat, and others in the same playbook.
  • DNS and NTP come from merged block.config.*. SSH: Polycrate sets ANSIBLE_PRIVATE_KEY_FILE in the container – no ssh_private_key in workspace.poly and no ansible_ssh_private_key_file in the playbook. See Ansible integration.

You can execute the action with:

polycrate run linux-mgmt update-linux

You don’t have to worry about the local installation of Ansible, Python, or SSH client – Polycrate starts a container with a complete toolchain (including Ansible, Python, SSH), as described in the Best Practices.


Windows Block: windows-mgmt with WinRM and ansible_os_family

The second block takes care of Windows hosts:

  • Install Windows updates
  • DNS and NTP basic configuration (via Ansible modules and PowerShell)

blocks/registry.acme-corp.com/acme/infra/windows-mgmt/block.polyname again as the full registry path without tag, analogous to the Linux block:

# name = from: without tag (full registry path)
name: "registry.acme-corp.com/acme/infra/windows-mgmt"
version: 0.1.0
kind: generic

config:
  dns_server: ""
  ntp_server: ""
  win_admin_user: ""
  win_admin_password: ""

actions:
  - name: update-windows
    description: Update Windows servers and set basic configuration
    playbook: windows_update.yml

The playbook blocks/registry.acme-corp.com/acme/infra/windows-mgmt/windows_update.yml:

- name: Update Windows hosts and set basic config
  hosts: windows_group
  gather_facts: true

  vars:
    ansible_user: "{{ block.config.win_admin_user }}"
    ansible_password: "{{ block.config.win_admin_password }}"
    dns_server: "{{ block.config.dns_server }}"
    ntp_server: "{{ block.config.ntp_server }}"

  tasks:
    - name: Check reachability
      ansible.windows.win_ping: {}

    - name: Install Windows updates
      ansible.windows.win_updates:
        category_names:
          - CriticalUpdates
          - SecurityUpdates
        reboot: yes

    - name: Set DNS server on network adapter
      ansible.windows.win_dns_client:
        adapter_names: "*"
        ipv4_addresses:
          - "{{ dns_server }}"
      when: ansible_os_family == 'Windows'

    - name: Configure Windows Time Service
      ansible.windows.win_shell: |
        w32tm /config /manualpeerlist:"{{ ntp_server }}" /syncfromflags:manual /reliable:yes /update
      when: ansible_os_family == 'Windows'

    - name: Restart Windows Time Service
      ansible.windows.win_service:
        name: W32Time
        state: restarted
      when: ansible_os_family == 'Windows'

Again:

  • hosts: windows_group uses the same inventory.yml as the Linux block.
  • ansible_user and ansible_password come from the encrypted workspace configuration via block.config, not in plain text from the inventory.
  • ansible_os_family == 'Windows' guards OS-specific tasks if you later extend the group (e.g. with appliances).

Run the action with:

polycrate run windows-mgmt update-windows

Because execution runs in a container, dependencies such as pywinrm are already included. With plain Ansible you would need to ensure on every admin machine:

  • a compatible Python version,
  • Ansible and the ansible.windows collection installed,
  • WinRM configured and tested.

Polycrate removes that setup overhead – the strength of the container model with Ansible, as described in the Ansible integration.


Workflow That Ties It Together: Linux First, Then Windows

The benefit of a shared workspace shows in the workflow. We already defined hybrid-maintenance in workspace.poly:

workflows:
  - name: hybrid-maintenance
    steps:
      - name: update-linux
        block: linux-mgmt
        action: update-linux
      - name: update-windows
        block: windows-mgmt
        action: update-windows

Run a full maintenance cycle with:

polycrate workflows run hybrid-maintenance

What happens:

  1. Polycrate starts a container and runs the update-linux action of block linux-mgmt.
  2. After success, it starts the next container and runs update-windows on block windows-mgmt.
  3. Order is fixed in the workflow – no more guessing who patches what first.

You can extend workflows with pre-checks (e.g. free disk space), maintenance windows, or post-checks (e.g. service health). Workflows connect blocks and help avoid unstructured playbook sprawl. See Workflows.


Polycrate vs. Plain Ansible in a Hybrid Setup

Compared to a classic setup, with plain Ansible you would typically:

  • Install Ansible locally on a Linux machine (watch Python versions).
  • Install and maintain Windows extras (e.g. pywinrm).
  • Maintain separate repos or folders for Windows playbooks and inventories.
  • Manage secrets with Ansible Vault, an external secrets manager, or ad-hoc storage.
  • Explain to colleagues which ansible-playbook commands to run in which order.

With Polycrate you get:

  • Dependency isolation in the container: Ansible, Python, WinRM dependencies, and tools like kubectl or helm ship in a defined toolchain – no workstation setup drift.
  • Sharable automation: Your linux-mgmt and windows-mgmt blocks can be shared via an OCI registry – internally or through PolyHub (reference scheme like registry.acme-corp.com/acme/infra/windows-mgmt:0.1.0; see PolyHub).
  • Guardrails from the block model: Playbooks gain structure via block.poly, workspace.poly, and workflows (Best Practices).
  • Better UX: Colleagues remember polycrate run windows-mgmt update-windows or polycrate workflows run hybrid-maintenance instead of raw Ansible CLI.
  • Built-in encryption: Secrets stay in the workspace and are stored encrypted – no extra vault product required.

Ansible remains the automation engine; Polycrate adds structure, reuse, and team focus.


Frequently Asked Questions

Can I add more operating systems to the same workspace?

Yes. The inventory can have any number of groups, and playbooks can branch on ansible_os_family or other facts. For macOS or appliances, add groups and either new blocks or more actions on existing blocks. Keep the pattern: clear blocks, clear inventory, clear workflows.

How does workspace encryption fit internal compliance (e.g. GDPR, ISO 27001)?

Polycrate workspace encryption uses age and encrypts sensitive files (SSH keys, passwords) in the repository. That gives you separation of config and plaintext secrets, traceable key rotation via Git history and CLI, and technical controls that map well to ISO 27001 and GDPR expectations (e.g. protecting access to production systems). Details: Workspace encryption.

How does ayedo help with hybrid workspaces?

We often work with teams that have grown Windows domains, new Linux workloads, and compliance requirements. In a hybrid workshop we shape:

  • a workspace structure that fits your organization,
  • Linux and Windows blocks (often from internal standards or existing Ansible playbooks),
  • workflows for patch days, onboarding servers, or baseline hardening.

On request we integrate monitoring, CMDB, ticketing, and help you build your own block registry.

More questions? See our FAQ.


From Routine to Reproducibility

With the hybrid workspace in this article you gain three things:

  1. One view of the infrastructure: Linux and Windows servers share one inventory and one workspace.
  2. Structured automation: Two blocks (linux-mgmt, windows-mgmt) wrap OS-specific playbooks; workflow hybrid-maintenance defines the sequence.
  3. Safe configuration: DNS/NTP and non-sensitive block parameters live in workspace.poly (and secrets.poly for passwords); the SSH key as a file under artifacts/secrets/, WinRM password in secrets.poly – with encryption enabled you only commit .age artifacts.

That turns the classic patch day – often a mix of manual steps, RDP, and ad-hoc scripts – into a reproducible, documented flow: a clear entry point (polycrate workflows run hybrid-maintenance), traceable changes (Git history plus Ansible logs), and reusable blocks for other workspaces or teams (internal registry or PolyHub).

At ayedo we help teams move from isolated scripts to reusable building blocks. Whether you come from Linux, Windows, or compliance – a shared hybrid workspace is a solid foundation for policies, hardening, monitoring, or self-service for other teams.

If you want to structure your hybrid infrastructure this way and learn from other environments, our Hybrid Infrastructure Workshop is a good starting point.

Hybrid Infrastructure Workshop

Ähnliche Artikel