Published on

OPA - Signing bundles

Authors
  • avatar
    Name
    Hieu Doan
    Twitter

In OPA, bundles can be digitally signed to prove that they come from a trusted source and to protect their integrity. This is a security measure to ensure that the bundles have not been tampered by a bad actor.

Signing a bundle in a nutshell is a two-steps process:

  • Use opa sign to generate a signature for the bundle.
  • Use opa build to create a signed bundle.

Steps

Use this example to get started with signing bundles: LINK

  1. Generate private and public keys

    # Private key: This will be used to sign a bundle:
    openssl genrsa -out private.pem 2048
    # Public key: This will be used to verify the bundle:
    openssl rsa -in private.pem -pubout -out public.pem
    
  2. Signing files in the bundle

    # Go to the bundle/ directory
    cd bundle
    
    # Usage of the sign command
    opa sign --help
    Generate an OPA bundle signature.
    The 'sign' command generates a digital signature for policy bundles. It generates a
    ".signatures.json" file that dictates which files should be included in the bundle,
    what their SHA hashes are, and is cryptographically secure.
    

    This command generates a hash for each file in the foo/ bundle folder, so if you change any of the files the hash will change:

    # Generate a new signature
    opa sign --signing-key ../private.pem --bundle foo -o foo/
    # Structure of the directory:
    tree -a
    .
    ├── bundles
    │   └── foo
    │       ├── .manifest
    │       ├── .signatures.json
    │       ├── bar
    │       │   └── data.json
    │       ├── input.json
    │       └── policy.rego
    ├── private.pem
    └── public.pem
    
    3 directories, 7 files
    
  3. Inspection of the .signatures.json file

    cat foo/.signatures.json
    
    {
      "signatures": [
        "eyJhbGciOiJSUzI1NiJ9.eyJmaWxlcyI6W3sibmFtZSI6ImZvby8ubWFuaWZlc3QiLCJoYXNoIjoiOWZkYWE3ZGM0YTMwMGIyYjIxZjljYTNmYjY2YzY0M2M0NzRhMmNhNGZiYzc3M2I2ZDY1YzhiNzc1MTZiNTk0YiIsImFsZ29yaXRobSI6IlNIQS0yNTYifSx7Im5hbWUiOiJmb28vYmFyL2RhdGEuanNvbiIsImhhc2giOiI1YWU3NWY2ZTU0MjUwZTIwNjBlNjUxNjY4NDVhNjkxNTI0MzZmZDU5YzY4NzNkZjdmZjI5YzUzODEzNTk4Y2ZhIiwiYWxnb3JpdGhtIjoiU0hBLTI1NiJ9LHsibmFtZSI6ImZvby9pbnB1dC5qc29uIiwiaGFzaCI6Ijg4YTU2ZjhkZDU5ODUyMTkxN2E3MTdmOWM0ODdlOTA3ZmFjYWQxMzM1M2Q3Mjk1NmI4YjkyNzE1MWQ4ODc0MWUiLCJhbGdvcml0aG0iOiJTSEEtMjU2In0seyJuYW1lIjoiZm9vL3BvbGljeS5yZWdvIiwiaGFzaCI6IjBkNGRhZGQ1MDFmNjA0NDEyZTgyZDlhYjIwZTBiYjYwMzhmYzA3YzE5MjVkMDU4Njg2NDExY2E1ZTRmZWExMzgiLCJhbGdvcml0aG0iOiJTSEEtMjU2In1dfQ.z8-nCY__MbrzuzYH1LpGVe6K2ONZGGWJ9vmGGNI9Ym-hNLd1C4GT-ddvZH9SqI7y5WafGbA_3rKnUSai77DXNvmCZ758I-XRUc7jJYg0O_z5q2y0dvjbSIZFT9iB2bOV39ZdOf3F2cuHR7elSI6d58Y89XaFBshMd7nnoY2BufhdRctffjVfVkHTbGnJy97KLcpspKtYk8UOMJu9N0cUkhePTOKbMni5ECvYRNl9SKeHY2-EFvQwpAg0EY9IvNJeGKqfCX0f_LMpb8DAnUU9n5JnIa7VlSBVAWsoySyMYI9QgHx2fs3V6t0fgiGInFOa87r-92FumrZNWhU8MS59Og"
      ]
    }
    

    Decode the signature - JSON Web Token (JWT)

    cat foo/.signatures.json | jq '.signatures[0]' | jwt
    
    (...)
    ✻ Header
    {
    "alg": "RS256"
    }
    
    ✻ Payload
     {
     "files": [
         {
         "name": "foo/.manifest",
         "hash": "9fdaa7dc4a300b2b21f9ca3fb66c643c474a2ca4fbc773b6d65c8b77516b594b",
         "algorithm": "SHA-256"
         },
         {
         "name": "foo/bar/data.json",
         "hash": "5ae75f6e54250e2060e65166845a69152436fd59c6873df7ff29c53813598cfa",
         "algorithm": "SHA-256"
         },
         {
         "name": "foo/input.json",
         "hash": "88a56f8dd598521917a717f9c487e907facad13353d72956b8b927151d88741e",
         "algorithm": "SHA-256"
         },
         {
         "name": "foo/policy.rego",
         "hash": "0d4dadd501f604412e82d9ab20e0bb6038fc07c1925d058686411ca5e4fea138",
         "algorithm": "SHA-256"
         }
     ]
     }
    (...)
    
  4. Sign and create the bundle archive

    In this step we will create an archive of the bundle and sign it with opa build.

    opa build --help                                                   ✔
    Build an OPA bundle.
    
    The 'build' command packages OPA policy and data files into bundles. Bundles are
    gzipped tarballs containing policies and data.(...)
    

    To do that we need to provide the following parameters:

    1. --verification-key: This is used to verify the signature (from step 2).
    2. --signing-key: This is used to sign the bundle by updating the .signatures.json file with a new signature. For the sake of this example I used the same private key from the step 1. But, you can generate a new one to sign the bundle.
    opa build --verification-key ../public.pem --signing-key ../private.pem --bundle foo -o foo.tar.gz
    
    # Structure
     tree -a
     .
     ├── foo
     │   ├── .manifest
     │   ├── .signatures.json # <--- Updated with a new signature
     │   ├── bar
     │   │   └── data.json
     │   ├── input.json
     │   └── policy.rego
     └── foo.tar.gz # <--- Generated by opa build
    
  5. Congratulations!

    Now you're bundle is signed. In next post we will verify the signed bundle with a local opa server.