Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

How to start configuration as code for an Ansible instance

May 27, 2025
Konstantin Kuminsky
Related topics:
Automation and management
Related products:
Red Hat Ansible Automation Platform

Share:

    It’s inevitable that a growing organization actively using Red Hat Ansible Automation Platform will face the challenge of managing the configuration of the Ansible Automation Platform as a code. The reasons leading to that may include various requirements for change management, consistency, and repeatability, to name a few.

    There is plenty of information on the configuration as code (CaC) approach, such as the benefits and challenges, but reiterating them is outside of the scope of this article. Going forward, we assume that the reader is well aware of why CaC is needed and how this approach can make a positive impact on the whole organization.

    If you're responsible for managing Ansible Automation Platform and have been tasked with implementing CaC, this series may be useful.

    • Part 1 (this article) is about first steps on the path of managing an existing Ansible Automation Platform instance as CaC: setting up Ansible Automation Platform accounts, collections, credentials, projects, and job templates required to run the automation, exporting configuration of some objects, handling secrets and special strings in the CaC, and managing configuration drift.

    • Part 2 will discuss completing the transition: exporting all objects, formatting configurations for readability, verification, access restrictions, and Git management.

    • Part 3 will deal with migrating configurations from AWX 24 to Ansible Automation Platform 2.5.

    • Part 4 will discuss migrating smart inventories (deprecated in future Ansible Automation Platform releases) to constructed inventories.

    • Part 5, the final article in this series, will discuss migrating configurations from Ansible Automation Platform 2.4 to Ansible Automation Platform 2.5.

    Collections requirements 

    For the purposes of this article, we assume the following:

    • You are using Ansible Automation Platform version 2.4 or 2.5 with Private Automation Hub.
    • You have a basic understanding of Ansible Automation Platform and its configuration via the web interface.
    • You are familiar with Ansible collections and their role in automation workflows.

    For mature organizations, the luxury of starting the Ansible Automation Platform configuration from scratch and using CaC right from the beginning is rare. Most likely there is already an existing instance of Ansible Automation Platform with hundreds or even thousands of different objects.

    Therefore, the very first requirement is the ability to export existing configurations in a structured format that can be used to maintain platform configuration directly or with minimal adjustments.

    To keep configurations up to date, the obvious requirement will be an ability to manage configuration drift. In other words, we need to be able to remove objects that are not needed anymore by removing them from the code, without the need to create additional cleanup playbooks.

    To cover both requirements, we will use the configify.aapconfig collection available from ansible-galaxy.

    Let’s start by creating an empty Git repository in the code management system of your choice and creating a collections/requirements.yml file with the following content:

    ---
    collections:
      - name: configify.aapconfig

    Assuming that the Ansible Automation Platform controllers are able to access the internet and that Private Hub is synchronizing Red Hat Certified Collections, this file should be enough to satisfy all collection requirements.

    For isolated environments (or if certified collections are missing in the Private Automation Hub), the following collections will need to be either synchronized to the Hub or imported there manually:

    • ansible.controller (Red Hat Hub)
    • infra.ah_configuration (Red Hat Hub)
    • ansible.platform (Red Hat Hub)
    • ansible.utils (Galaxy)
    • ansible.hub (Galaxy)

    Consult the most recent version of the collection’s galaxy.yml file for specific version requirements.

    Collection synchronization or import is outside of the scope of this article. Check the official Red Hat documentation for detailed steps.

    At this point, all the required collections should be downloaded automatically during the project synchronization, assuming that the Ansible Automation Platform organization we are going to use for CaC jobs has been assigned the correct credentials for accessing Galaxy and Private Automation Hub.

    We will create a project during the following steps.

    Accounts and tokens requirements

    To configure the Ansible Automation Platform controller and hub, you must have an account with full administrative access. In Ansible Automation Platform 2.4 there are two separate sets of accounts for each of the components. The recommended practice is to have a separate account for automation tasks. So we will need two new administrative accounts for Ansible Automation Platform 2.4.

    Once you've created those accounts, let’s generate API tokens for them. In Controller and Gateway, this is done from User Details | Tokens. Tokens should have read/write scope. Make sure to copy the values as they will be shown only once. We will use them in Ansible Automation Platform credentials during the following steps.

    Unfortunately for Private Hub, we will have to use passwords for now. As of the time of writing, some of the dependency collections do not support tokens for some modules.

    The recommendation for separate automation accounts is driven by manageability and auditing considerations. For Hub, since token retrieval operation resets the token, a separate account reduces the risk of token invalidation by another process or user. 

    The choice to use API tokens instead of account passwords helps to keep Ansible Automation Platform configuration tasks independent from any account password rotation, simplifies management, and improves security, since there is no need to store token values once they’ve been supplied to a credential. At the same time, this choice simplifies secret rotation which you can do by generating a new token, replacing it in automation credentials at your convenience while the old token is still valid, and deleting the old token later.

    Ansible configuration requirements

    To finalize the preparation, let’s log in to Ansible Automation Platform and create the following:

    • Credential of type Red Hat Ansible Automation Platform for accessing Controller, specifying Controller URL, and API token created at the previous step.

      For Ansible Automation Platform 2.5, the controller URL should be set to Gateway URL because of unified authentication.

    • Credential type for future hub credential.

      In the input field, specify variables for URL, username, and token:

      fields:
        - id: hub_url
          type: string
          label: HubURL
        - id: hub_user
          type: string
          label: HubUser
        - id: hub_password
          type: string
          label: HubPassword
          secret: true

      In the Injector Configuration field, expose these variables as environment variables:

      env:
        AH_HOST: '{{ hub_url }}'
        AH_USERNAME: '{{ hub_user }}'
        AH_PASSWORD: '{{ hub_password }}'

      To be able to connect to nodes using self-signed SSL certificates, you may need to expose AH_VERIFY_SSL. For Ansible Automation Platform 2.5, make sure that the Hub URL is set to Gateway URL.

    • Credential of the type created at the previous step, specifying the Hub URL and the automation username and password.
    • For Ansible Automation Platform 2.5, we will need credential type and credential for Gateway. Follow the previous two steps and expose the following environment variables:

      GATEWAY_HOSTNAME
      GATEWAY_API_TOKEN
      (GATEWAY_VERIFY_SSL)
    • An inventory without any hosts. Ansible Automation Platform configuration jobs will run against localhost but an inventory can be empty since localhost is implied for each Ansible Automation Platform Inventory by default.
    • A project of type Git, pointing to the previously created repository. If the repository requires authentication, create a source control credential and associate it with the project.

      Once configured, trigger a project synchronization and verify the logs to confirm successful collection retrieval.

    • For Ansible Automation Platform 2.4, specify the correct API URL prefix under Settings > Job settings > Edit > Extra Environment Variables:

      {
        "CONTROLLER_OPTIONAL_API_URLPATTERN_PREFIX": "/api/"
      }

    Export objects

    At this point, we should be able to perform configuration exports. Let’s start with simpler objects: organizations and users.

    Add two playbooks in the Git repository created earlier: a wrapper to export organizations calling the corresponding playbook from the configify.aapconfig collection.

    ---
    - name: Run playbook to export organizations
      import_playbook: configify.aapconfig.aap_audit_organizations.yml

    As well as another playbook for user export:

    ---
    - name: Run playbook to export users
      import_playbook: configify.aapconfig.aap_audit_users.yml

    Synchronize the project created earlier and create a job template using credentials, inventory, and project. For the playbook, select the one for organizations export and launch the job.

    Once the job finishes, the last task contains a structure describing the existing organization configuration, which looks like this:

    "controller_objects_organizations": [
      "{'name': 'Default', 'descr': '', 'creds': ['Ansible Galaxy', 'Private Hub']}",
      "{'name': 'Org B', 'descr': '', 'creds': ['Credential B']}",
      "{'name': 'Org C', 'descr': 'Org C', 'creds': ['Credential C', 'Credential C2']}"
    ]

    Let’s remove the double quotes generated by the Ansible Automation Platform to get a list of dictionaries:

    controller_objects_organizations: [
      {'name': 'Default', 'descr': '', 'creds': ['Ansible Galaxy', 'Private Hub']},
      {'name': 'Org B', 'descr': '', 'creds': ['Credential B']},
      {'name': 'Org C', 'descr': 'Org C', 'creds': ['Credential C', 'Credential C2']}
    ]

    This structure is going to become one of the variables in CaC describing Ansible Automation Platform configuration.

    Next run the playbook for user export to get the controller_objects_users variable:

    controller_objects_users: [
      {'username': 'UserB', 'first_name': 'bbb', 'last_name': '', 'email': '',
       'superuser': False, 'auditor': False, 'pass': '$encrypted$'},
      {'username': 'UserB_Superuser', 'first_name': 'bbbsss', 'last_name': '', 'email': '',
       'superuser': True, 'auditor': False, 'pass': '$encrypted$'},
      {'username': 'UserC', 'first_name': 'ccc', 'last_name': 'ccc', 'email': '',
       'superuser': False, 'auditor': False, 'pass': '$encrypted$'},
      {'username': 'UserC_Auditor', 'first_name': 'cccaaa', 'last_name': 'ccaa', 'email': '',
       'superuser': False, 'auditor': True, 'pass': '$encrypted$'},
      {'username': 'admin', 'first_name': '', 'last_name': '', 'email': 'admin@example.com',
       'superuser': True, 'auditor': False, 'pass': '$encrypted$'},
      {'username': 'automation', 'first_name': 'automation', 'last_name': '', 'email': '',
       'superuser': True, 'auditor': False, 'pass': '$encrypted$'}
    ]

    Verify configurations

    Once the configurations have been retrieved, let’s verify they are valid and can be used for CaC going forward. To do that, we need to create a new file in the repository with configurations obtained at the previous step and add another wrapper playbook:

    - name: Include vars
      hosts: localhost
      gather_facts: false
      tasks:
        - name: Include variables
          ansible.builtin.include_vars: all_aap_objects
          tags: always
    - name: Run playbook to configure AAP
      import_playbook: configify.aapconfig.aap_configure.yml

    This playbook adds variables with objects from the file to the play and runs the Ansible Automation Platform configuration playbook from the aapconfig collection.

    Synchronize the project and run the job template with the new playbook in check mode. Since we are verifying organizations and user configurations, let’s run the job with the following tags:

    controller_config_organizations_apply
    controller_config_users_apply

    Of course, the expectation is that there should be no tasks reporting a change:

    PLAY [Include vars] ************************************************************
    TASK [Set controller hostname] *************************************************
    ok: [localhost]
    TASK [Include all vars] ********************************************************
    ok: [localhost]
    PLAY [Configure AAP] ***********************************************************
    TASK [Determine AAP version] ***************************************************
    ok: [localhost]
    TASK [configify.aapconfig.controller_config : USERS - Create users (2.5)] ******
    skipping: [localhost] => (item= | user: UserB) 
    skipping: [localhost] => (item= | user: UserB_Superuser) 
    skipping: [localhost] => (item= | user: UserC) 
    skipping: [localhost] => (item= | user: UserC_Auditor) 
    skipping: [localhost]
    TASK [configify.aapconfig.controller_config : USERS - Make user an auditor if required (2.5)] ***
    skipping: [localhost] => (item= | user: UserB) 
    skipping: [localhost] => (item= | user: UserB_Superuser) 
    skipping: [localhost] => (item= | user: UserC) 
    skipping: [localhost] => (item= | user: UserC_Auditor) 
    skipping: [localhost]
    TASK [configify.aapconfig.controller_config : USERS - Create or modify users (pre 2.5)] ***
    ok: [localhost] => (item= | user: UserB)
    ok: [localhost] => (item= | user: UserB_Superuser)
    ok: [localhost] => (item= | user: UserC)
    ok: [localhost] => (item= | user: UserC_Auditor)
    TASK [configify.aapconfig.controller_config : ORGANIZATIONS - Create or modify organizations (2.5)] ***
    skipping: [localhost] => (item= | organization: Org B) 
    skipping: [localhost] => (item= | organization: Org C) 
    skipping: [localhost]
    TASK [configify.aapconfig.controller_config : ORGANIZATIONS - Create (pre 2.5) or modify organizations] ***
    ok: [localhost] => (item= | organization: Org B)
    ok: [localhost] => (item= | organization: Org C)
    PLAY RECAP *********************************************************************
    localhost                  : ok=5    changed=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0  

    This confirms that our configurations work and are correct.

    Handling objects with secrets

    Note that the user accounts exported from Ansible Automation Platform earlier don't contain any passwords. This is because secrets are encrypted in Ansible Automation Platform and can not be retrieved. There are several ways to address this challenge in CaC:

    • We can choose not to handle passwords in configuration and instead rely on users or administrators to manually update the credentials they own. This approach may be enough at the beginning or as a temporary solution, but in the long run, it will stand in the way of achieving full automation from start to finish.
    • Alternatively, we could use Ansible Vault. Passwords and other secrets can be encrypted and used directly in CaC. This solution may be suitable for smaller deployments, but it doesn’t seem to be scalable for larger environments. It also requires additional scripts should regular password rotation be needed.
    • The third approach seems to address the downsides of the two previous ones. The secrets will be stored in an external secret management system and retrieved using a lookup plug-in during the playbook run. For example, for HashiCorp, such retrieval looks similar to the following:
    'pass': lookup('community.hashi_vault.hashi_vault', 'secret=secret/hello:value auth_method=approle role_id=hashi_roleid secret_id=hashi_secretid')

    Certainly, this solution adds to the requirements. Specifically, we will need to add community.hashi_vault collection to requirements.yml and create additional Ansible Automation Platform credential type and credential to store role_id and secret_id values.

    One of these approaches needs to be taken with all Ansible Automation Platform objects containing secrets, such as users, credentials, and some notification profiles.

    By default, the configify.aapconfig collection doesn’t update secrets. When such change is required, run the configify.aapconfig.aap_configure.yml playbook specifying in the job template’s variables as follows:

    replace_passwords: true

    This switch makes all tasks that handle objects with secrets not idempotent since the Ansible Automation Platform has no way of telling if secrets changed.

    Handling objects with special characters

    Let’s create another wrapper playbook to export credential types and run it:

    - name: Run playbook to get credential types
      import_playbook: configify.aapconfig.aap_audit_credential_types.yml

    The output will look similar to the following:

    controller_objects_credential_types: [
      {'name': 'Credential Type B', 'descr': '',
       'inputs': {'fields': [{'id': 'usernameB', 'type': 'string', 'label': 'Username'},
                             {'id': 'passwordB', 'type': 'string', 'label': 'Password'}]},
       'injectors': {'extra_vars': {'configifyadpass': '{{ passwordB }}',
                                    'configifyaduser': '{{ usernameB }}'}}},
      {'name': 'Credential Type C', 'descr': '',
       'inputs': {'fields': [{'id': 'usernameC', 'type': 'string', 'label': 'Username'},
                             {'id': 'passwordC', 'type': 'string', 'label': 'Password'}]},
       'injectors': {'extra_vars': {'configifyadpass': '{{ passwordC }}',
                                    'configifyaduser': '{{ usernameC }}'}}},
      {'name': 'Hub type', 'descr': '',
       'inputs': {'fields': [{'id': 'hub_url', 'type': 'string', 'label': 'HubURL'},
                             {'id': 'hub_user', 'type': 'string', 'label': 'HubUser'},
                             {'id': 'hub_pass', 'type': 'string', 'label': 'HubPass', 'secret': True}]},
       'injectors': {'env': {'AH_HOST': '{{ hub_url }}',
                             'AH_USERNAME': '{{ hub_user }}',
                             'AH_API_TOKEN': '{{ hub_pass }}'}}}
    ]

    Double curly brackets in the output will certainly be a problem when running configuration playbooks since {{ }} in the Ansible Automation Platform represents a variable, while values from the output should be handled as strings.

    The solution is simple. We need to add a key !unsafe in front of each problematic value as follows:

      {'name': 'Hub type', 'descr': '',
       'inputs': {'fields': [{'id': 'hub_url', 'type': 'string', 'label': 'HubURL'},
                             {'id': 'hub_user', 'type': 'string', 'label': 'HubUser'},
                             {'id': 'hub_pass', 'type': 'string', 'label': 'HubPass', 'secret': True}]},
       'injectors': {'env': {'AH_HOST': !unsafe '{{ hub_url }}',
                             'AH_USERNAME': !unsafe '{{ hub_user }}',
                             'AH_API_TOKEN': !unsafe '{{ hub_pass }}'}}}

    Another area of concern is quotes and backslashes in object fields such as names and usernames. Consider the following export:

    controller_objects_credentials_organizational: [
      {'name': 'Credential with \"quotes\"', 'org': 'Org B', 'descr': '', 'type': 'Machine',
       'inputs': {'password': 'HIDDEN', 'username': 'domain\\\\user'},
       'src_input_field_name': '', 'src_credential': '', 'src_metadata': ''}

    The Ansible Automation Platform added backslashes in front of the double quotes in the credential name and multiple backslashes in the Active Directory username. It will consider such a configuration as a new credential during the import, and it will be created with a username containing multiple backslashes. To avoid this, simply remove unwanted characters before applying the configuration:

    controller_objects_credentials_organizational: [
      {'name': 'Credential with "quotes"', 'org': 'Org B', 'descr': '', 'type': 'Machine',
       'inputs': {'password': 'HIDDEN', 'username': 'domain\user'},
       'src_input_field_name': '', 'src_credential': '', 'src_metadata': ''}

    Manage configuration drift

    Finally, we need to make sure the tool we use can handle these two cases:

    • If there is an object or setting in the Ansible Automation Platform that is missing in the CaC, we would like to know about that and be able to delete them if we choose so.
    • If there is an object that is not needed anymore, we want to simply remove it from CaC and watch the removal from Ansible Automation Platform during the next run.

    Let’s verify that both situations are handled properly using organizations configuration retrieved earlier as an example. To do that, we are going to manually create a "rogue organization" in Ansible Automation Platform via the web interface and remove "Org C" from the file with objects in the repository.

    Now let’s run the configuration playbook specifying a controller_config_organizations tag. The job should report both organizations as rogue:

    <…>
    TASK [configify.aapconfig.controller_config : ORGANIZATIONS - Notify on rogue organizations] ***************************************************************
    skipping: [localhost] => (item= | organization: Default)
    skipping: [localhost] => (item= | organization: Org B)
    changed: [localhost] => (item= | organization: Org C) => {
        "msg": "Shouldn't be there"
    }
    changed: [localhost] => (item= | organization: Rogue Organization) => {
        "msg": "Shouldn't be there"
    }
    <…>
    TASK [configify.aapconfig.controller_config : ORGANIZATIONS - Delete rogue organizations (pre 2.5)] ************************************************************
    skipping: [localhost] => (item= | organization: Default)
    skipping: [localhost] => (item= | organization: Org B)
    skipping: [localhost] => (item= | organization: Org C)
    skipping: [localhost] => (item= | organization: Rogue Organization)
    skipping: [localhost]
    <…>

    By default it deletes nothing. To force deletion, run the job specifying an extra variable:

    delete_objects: true

    Final thoughts

    This concludes the first part of the series. Using the right tools for configuring Ansible Automation Platform with the configuration as code approach makes this task easy and rewarding.

    Stay tuned for the next article where we'll discuss CaC automation from start to finish and aspects of access and Git processes you should consider afterwards.

    Related Posts

    • How to deploy applications using Ansible Automation Platform

    • Install containerized Ansible Automation Platform on RHEL 9.2

    • How to use Ansible Automation Platform from Azure Marketplace

    • How to build virtual machines using Ansible Collections

    Recent Posts

    • GuideLLM: Evaluate LLM deployments for real-world inference

    • Unleashing multimodal magic with RamaLama

    • Integrate Red Hat AI Inference Server & LangChain in agentic workflows

    • Streamline multi-cloud operations with Ansible and ServiceNow

    • Automate dynamic application security testing with RapiDAST

    What’s up next?

    Discover Ansible Content Collections through practical examples that explain their advantages, and then create and use them in your Ansible automation in this learning path.

    Start the activity
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue