Start Building for Free
CircleCI.comAcademyBlogCommunitySupport

Manage contexts with config policies

3 weeks ago11 min read
Cloud
Server v4.x
On This Page

Follow this how-to guide to create config policies for managing the use of contexts in your organization. For more information about config policies, see the Config policies overview.

Introduction

Config policies use a decision engine leveraging OPA ( Open Policy Agent) to allow you to specify policies, and return a decision about whether a pipeline’s config complies with those policies. In the strictest case, if a pipeline configuration does not comply with the organisation’s policies, that pipeline will be blocked from triggering until it does comply.

Well-designed secrets management is a delicate balancing act between security and usability. To help with this balance, you can lock down contexts at different levels using config policies.

This how-to guide presents a selection of helpers (CircleCI-specific rego functions) that are likely to be useful for you when writing policies around the use of contexts in your organization.

The contexts helpers covered are as follows:

In the examples on this page, project IDs, branch names, and context names can be supplied using the following types:

  • String

  • Set of strings

  • Array of strings

Prerequisites

  • A CircleCI account connected to a supported VCS.

  • Install/update the CircleCI CLI, and ensure you have authenticated with a token before attempting to use the CLI with config policies. See the Installing the Local CLI page for more information.

  • Ensure you have enabled config policy evaluation for your organization so that project configurations will be evaluated against your organization’s policies when pipelines are triggered:

    circleci policy settings --enabled=true --owner-id <your-organization-ID>

    Example output:

    {
      "enabled": true
    }
  • It is recommended to run through the Create a policy and Manage policies with your VCS guides first. Best practice is to use a repository within your organization to store and develop your policies. The Manage policies with your VCS guide walks through setting this up and setting up a pipeline for policy development.

  • To use the examples set out on this page, you will need to be using contexts to store secrets. For more information, see the Using contexts page.

Define the contexts allowed for a project

There are many reasons why you may want to allow specific projects the use of only certain contexts. For example, you might want to only allow contexts that have EKS-related deployment keys to projects architected to be deployed on EKS using those keys.

To achieve this, use the contexts_allowed_by_project_ids helper to create a policy to apply this restriction. This helper function accepts project IDs and context names, and prevents the usage of contexts that are not in the allow-list for all specified projects.

1. Create your policy

  1. If you have not already done so, create an empty directory to store your policies. For example:

    mkdir ./config-policies
  2. Create a new file in this directory for your new policy. Name the file allow_contexts.rego.

  3. Copy the following snippet into the allow_contexts.rego file you just made:

    # All policies start with the org package definition
    package org
    
    # import CircleCI specific helper functions
    import data.circleci.config
    
    # Declare a policy name
    policy_name["contexts_allowed_by_project"]
    
    # Declare a rule
    rule_contexts_allowed_by_project_ids = config.contexts_allowed_by_project_ids{
        ["<project-ID>"],
        ["<context-1>","<context-2>"]
    }
    
    # Enable the rule and choose the hard_fail enforcement level
    enable_hard["rule_contexts_allowed_by_project_ids"]

    In the following steps you will replace <project-ID> and <context-1> (and <context-2> if you choose to use more than one) with your projects and contexts. The allow_contexts.rego policy, once uploaded, will restrict your specified project to only have access to the context(s) in your allow-list.

2. Update policy with your details

  1. Replace <project-ID> with the ID for the project you want to restrict:

    • In the CircleCI web app, select Projects from the sidebar, and click the ellipsis (…​) next to your project, and select Project Settings to locate the Project ID.

  2. Replace <context-1> with the name of the context you want to allow the use of. You can add multiple contexts as an array, or stick with one for now.

    • To find a list of your contexts, select Organization settings from the sidebar in the CircleCI web app and then select Contexts from the menu.

3. Push up your policy bundle

You can now push your new policy to your organization for it to take effect. You have two options:

  • Push the policy manually using the CLI from your local environment

  • Push your changes to your config policy repository if you are managing policies via your VCS as shown in the Manage policies with your VCS guide.

Conclusion

Once you have pushed your new allow_contexts.rego policy, if an attempt to trigger a pipeline is made, in which the specified project has access to contexts in the block-list configured in your policy, the pipeline will fail to trigger. Developers will be notified on the dashboard as shown below.

Dashboard page

Use sets and variables

In this example, you have hard coded your project IDs and context names into your policy. This hard coding is not ideal as it makes the policies hard to read and understand. A better way is to use sets and variables defined in separate .rego files. To use this method, follow these steps:

  1. Create three files for your contexts and IDs: project_ids.rego, project_groups.rego and context_groups.rego so you end up with the following file structure:

    ├── config-policies/
    │   ├── allow_contexts.rego
    │   ├── project_ids.rego
    │   ├── project_groups.rego
    │   ├── context_groups.rego
  2. Add the following to your new .rego files, and replace IDs and context names shown between < > with your data as shown in the previous section:

    • project_id.rego

      # Single application project IDs. Can be automated.
      my_project_id := “<project-ID>”
    • project_groups.rego

      # sets can be used to group variables
      Front_end_applications := {my_project_id}
    • context_groups.rego

      # sets can be used to group variables
      Front_end_application_contexts := {"<context-1>","<context-2>"}
  3. You can now rewrite your allow_policy.rego policy as follows:

    # All policies start with the org package definition
    package org
    
    # import CircleCI specific helper functions
    import data.circleci.config
    
    # Declare a policy name
    policy_name["contexts_allowed_by_sample_project"]
    
    # Declare a rule
    rule_contexts_allowed_by_project_ids = config.contexts_allowed_by_project_ids{
        Front_end_applications,
        Front_end_application_contexts
    }
    
    # Enable the rule and choose the hard_fail enforcement level
    enable_hard["rule_contexts_allowed_by_project_ids"]

Define the contexts blocked for a project

To add an extra layer of security to secrets management, you may wish to block access to certain contexts for projects that should not have access to their secrets for security or compliance reasons.

Use the contexts_blocked_by_project_ids helper to create a policy to apply this restriction. This helper function accepts project IDs and context names, and prevents the usage of any contexts in the block-list for all specified projects.

1. Create your policy

  1. If you have not already done so, create an empty directory to store your policies. For example:

    mkdir ./config-policies
  2. Create a new file in this directory for your new policy. Name the file block_contexts.rego.

  3. Copy the following snippet into the block_contexts.rego file you just made:

    # All policies start with the org package definition
    package org
    
    # import CircleCI specific helper functions
    import data.circleci.config
    
    # Declare a policy name
    policy_name["contexts_blocked_by_sample_project"]
    
    # Declare a rule
    rule_contexts_blocked_by_project_ids = config.contexts_blocked_by_project_ids{
        ["<project-ID>"],
        ["<context-1>","<context-2>"]
    }
    
    # Enable the rule and choose the hard_fail enforcement level
    enable_hard["rule_contexts_blocked_by_project_ids"]

    In the following steps you will replace <project-ID> and <context-1> (and <context-2> if you choose to use more than one) with your projects and contexts. The block_contexts.rego policy, once uploaded, will restrict your specified project so that it will not have access to the context(s) in your block-list.

2. Update policy with your details

  1. Replace <project-ID> with the ID for the project you want to restrict:

    • In the CircleCI web app, select Projects from the sidebar, and click the elipsis (…​) next to your project. Select Project Settings to locate the Project ID.

  2. Replace <context-1> with the name of the context you want to block the use of. You can add multiple contexts as an array, or stick with one for now.

    • To find a list of your contexts, select Organization settings from the sidebar in the CircleCI web app and then select Contexts from the menu.

3. Push up your policy bundle

You can now push your new policy to your organization for it to take effect. You have two options:

  • Push the policy manually using the CLI from your local environment, or;

  • Push your changes to your config policy repository if you are managing policies via your VCS as shown in the Manage policies with your VCS guide.

Conclusion

Once you have pushed your new block_contexts.rego policy, if an attempt to trigger a pipeline is made, in which the specified project has access to contexts in the block-list configured in your policy, the pipeline will fail to trigger. Developers will be notified on the dashboard as shown below.

Dashboard page showing fail

Define the contexts reserved by a project

You may want to reserve contexts for use by a defined list of projects, blocking the use of those contexts by any project not in the allow-list. One possible use case for this would be locking contexts containing deployment keys to only those applications (projects) that need it. Any app that does not need this access will not be able to access those contexts. Developers will receive a hard fail, and pipelines will fail to trigger.

Use the contexts_reserved_by_project_ids helper to create a policy to apply this restriction. This helper function accepts project IDs and context names. It prevents the usage of any reserved contexts for projects that are not in the allow-list.

1. Create your policy

  1. If you have not already done so, create an empty directory to store your policies. For example:

    mkdir ./config-policies
  2. Create a new file in this directory for your new policy. Name the file reserve_contexts.rego.

  3. Copy the following snippet into the reserve_contexts.rego file you just made:

    # All policies start with the org package definition
    package org
    
    # import CircleCI specific helper functions
    import data.circleci.config
    
    # Declare a policy name
    policy_name["reserved_contexts"]
    
    # Declare a rule
    rule_reserve_contexts = config.contexts_reserved_by_project_ids{
        ["<project-ID-1>","<project-ID-1>"],
        ["<context-1>","<context-2>"]
    }
    
    # Enable the rule and choose the hard_fail enforcement level
    enable_hard["rule_reserve_contexts"]

    In the following steps you will replace <project-ID-1> and <context-1> (and <project-ID-2> and <context-2> if you choose to use more than one) with your projects and contexts. The reserve_contexts.rego policy, once uploaded, will restrict your specified context(s) so that they can only be used by the project(s) you have added to the allow-list.

2. Update policy with your details

  1. Replace <project-ID-1> with the ID for the first project you want to add to the allow-list. You can add multiple project IDs as an array, or stick with one for now:

    • In the CircleCI web app, select Projects from the sidebar, and click the elipsis (…​) next to your project, and select Project Settings to locate the Project ID.

  2. Replace <context-1> with the name of the first context you want to restrict the use of. You can add multiple contexts as an array, or stick with one for now.

    • To find a list of your contexts, select Organization settings from the sidebar in the CircleCI web app and then select Contexts from the menu.

3. Push up your policy bundle

You can now push your new policy to your organization for it to take effect. You have two options:

  • Push the policy manually using the CLI from your local environment, or;

  • Push your changes to your config policy repository if you are managing policies via your VCS as shown in the Manage policies with your VCS guide.

Conclusion

Once you have pushed your new reserve_contexts.rego policy, if an attempt to trigger a pipeline is made for a project outside your allow-list, in which the project tries to access contexts in the reserved-list configured in your policy, the pipeline will fail to trigger. Developers will be notified on the dashboard as shown below.

Define the contexts reserved by a branch

You may want to restrict which contexts (and therefore secrets) are available depending on which branch is being built. Using branch-based restrictions, you can manage your application environment in one repository, and lock down the use of secrets to individual branches. For example, you could split up production secrets and development secrets. This allows you to ensure that production secrets cannot be accessed by a build on a development branch.

Use the contexts_reserved_by_branches helper to define a policy for this use case. This helper function accepts branch names and context names. Only pipelines running on specified branches are allowed access to contexts in the allow-list.

1. Create your policy

  1. If you have not already done so, create an empty directory to store your policies. For example:

    mkdir ./config-policies
  2. Create a new file in this directory for your new policy. Name the file context_protection.rego.

  3. Copy the following snippet into the context_protection.rego file you just made:

    # All policies start with the org package definition
    package org
    
    # import CircleCI specific helper functions
    import data.circleci.config
    
    # Declare a policy name
    policy_name["prod_context_protection"]
    
    # Declare a rule
    use_prod_context_on_main = config.contexts_reserved_by_branches{["main"],
        ["<context-1>","<context-2>"]
    }
    
    # This rule will apply to all projects subscribed in project_groups.rego under policy_restrict_context_access
    enable_rule["use_prod_context_on_main"]{
        policy_restrict_context_access[data.meta.project_id]
    }
    hard_fail["use_prod_context_on_main"]
  4. Create a second rego file, names project_groups.rego to specify an additional restriction on which projects are affected by this rule. Replace <project-ID> with one of your project IDs

    project_groups.rego

    # sets can be used to group variables
    policy_restrict_context_access := <project-ID>

In the following steps you will replace <context-1> (and <context-2> if you choose to use more than one) with your context name. The context_protection.rego policy, once uploaded, will restrict use of your specified context(s) to builds on the main branch, for projects specified in project_groups.rego.

2. Update policy with your details

  1. Replace <context-1> with the name of the context you want to allow the use of. You can add multiple contexts as an array, or stick with one for now.

    • To find a list of your contexts, select Organization settings from the sidebar in the CircleCI web app and then select Contexts from the menu.

3. Push up your policy bundle

You can now push your new policy to your organization for it to take effect. You have two options:

  • Push the policy manually using the CLI from your local environment, or;

  • Push your changes to your config policy repository if you are managing policies via your VCS as shown in the Manage policies with your VCS guide.

Conclusion

Once you have pushed your new context_protection.rego policy, if an attempt to trigger a pipeline on a branch other than main is made, in which production contexts are used, the pipeline will fail to trigger. Developers will also be notified on the dashboard.


Suggest an edit to this page

Make a contribution
Learn how to contribute