Skip to content

Infrastructure & Config Management Guide

Artifact Keeper provides native support for infrastructure-as-code and configuration management package formats.

Terraform

Endpoint

Terraform operations use the /terraform/{repo} endpoint:

http://localhost:8080/terraform/{repo}

Alternative formats:

  • Key: terraform
  • Alias: opentofu

Clients

Compatible with:

  • terraform - HashiCorp Terraform
  • tofu - OpenTofu (open-source Terraform fork)

Module Configuration

Configure Module Source

In your Terraform configuration:

module "vpc" {
source = "localhost:8080/terraform/modules/vpc"
version = "1.0.0"
}

Registry Block

Configure Terraform to use Artifact Keeper as a module source:

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
module "networking" {
source = "localhost:8080/terraform/modules/networking"
version = ">= 1.0.0"
}

Provider Mirror Configuration

Configure Terraform to use Artifact Keeper as a provider mirror.

CLI Configuration

Create or edit ~/.terraformrc (Linux/macOS) or %APPDATA%/terraform.rc (Windows):

provider_installation {
network_mirror {
url = "http://localhost:8080/terraform/providers/"
}
}

With Authentication

provider_installation {
network_mirror {
url = "http://localhost:8080/terraform/providers/"
include = ["registry.terraform.io/*/*"]
}
}
credentials "localhost:8080" {
token = "your-api-token"
}

Publishing Modules

Module Structure

Standard Terraform module structure:

terraform-vpc-aws/
├── main.tf
├── variables.tf
├── outputs.tf
├── README.md
├── LICENSE
└── examples/
└── basic/
└── main.tf

Module Metadata

Create terraform-registry-manifest.json:

{
"version": 1,
"metadata": {
"name": "vpc",
"namespace": "mycompany",
"provider": "aws",
"version": "1.0.0",
"source": "https://github.com/mycompany/terraform-vpc-aws"
}
}

Publishing via HTTP

Terminal window
# Create module archive
tar -czf terraform-vpc-aws-1.0.0.tar.gz -C terraform-vpc-aws .
# Upload to registry
curl -X PUT \
-H "Authorization: Bearer your-token" \
-F "file=@terraform-vpc-aws-1.0.0.tar.gz" \
http://localhost:8080/terraform/modules/mycompany/vpc/aws/1.0.0

Using Terraform Init

Terminal window
# Initialize and install modules
terraform init
# Upgrade modules
terraform init -upgrade

Version Constraints

In module sources:

# Exact version
module "vpc" {
source = "localhost:8080/terraform/modules/vpc"
version = "1.0.0"
}
# Version range
module "vpc" {
source = "localhost:8080/terraform/modules/vpc"
version = ">= 1.0.0, < 2.0.0"
}
# Pessimistic constraint
module "vpc" {
source = "localhost:8080/terraform/modules/vpc"
version = "~> 1.0"
}

OpenTofu

Artifact Keeper works seamlessly with OpenTofu:

Terminal window
# Use same configuration files
tofu init
tofu plan
tofu apply

Vagrant

Endpoint

Vagrant operations use the /vagrant/{repo} endpoint:

http://localhost:8080/vagrant/{repo}

Key: vagrant

Box Configuration

Add Box from Registry

Terminal window
# Add box from Artifact Keeper
vagrant box add mycompany/ubuntu \
--box-version 20.04 \
--provider virtualbox \
http://localhost:8080/vagrant/boxes/mycompany/ubuntu.json

Vagrantfile Configuration

Vagrant.configure("2") do |config|
config.vm.box = "mycompany/ubuntu"
config.vm.box_version = "20.04"
config.vm.box_url = "http://localhost:8080/vagrant/boxes/mycompany/ubuntu.json"
config.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
vb.cpus = 2
end
end

Publishing Boxes

Create Box Metadata

Create ubuntu.json:

{
"name": "mycompany/ubuntu",
"description": "Ubuntu 20.04 LTS",
"versions": [
{
"version": "20.04",
"providers": [
{
"name": "virtualbox",
"url": "http://localhost:8080/vagrant/boxes/mycompany/ubuntu/20.04/virtualbox.box",
"checksum_type": "sha256",
"checksum": "abc123..."
}
]
}
]
}

Upload Box

Terminal window
# Create box from existing VM
vagrant package --output ubuntu-20.04.box
# Upload box file
curl -X PUT \
-H "Authorization: Bearer your-token" \
-F "file=@ubuntu-20.04.box" \
http://localhost:8080/vagrant/boxes/mycompany/ubuntu/20.04/virtualbox.box
# Upload metadata
curl -X PUT \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d @ubuntu.json \
http://localhost:8080/vagrant/boxes/mycompany/ubuntu.json

Downloading Boxes

Terminal window
# List available boxes
vagrant box list
# Update boxes
vagrant box update
# Remove box
vagrant box remove mycompany/ubuntu --box-version 20.04

Chef

Endpoint

Chef operations use the /chef/{repo} endpoint:

http://localhost:8080/chef/{repo}

Key: chef

Clients

Compatible with:

  • knife - Chef command-line tool
  • berkshelf - Cookbook dependency manager

Supermarket Configuration

Knife Configuration

Create or edit ~/.chef/config.rb:

current_dir = File.dirname(__FILE__)
node_name "your-username"
client_key "#{current_dir}/your-username.pem"
chef_server_url "http://localhost:8080/chef/organizations/mycompany"
cookbook_path ["#{current_dir}/../cookbooks"]
# Supermarket configuration
knife[:supermarket_site] = 'http://localhost:8080/chef/supermarket'

Berkshelf Configuration

Create or edit ~/.berkshelf/config.json:

{
"chef": {
"chef_server_url": "http://localhost:8080/chef/organizations/mycompany",
"node_name": "your-username",
"client_key": "/path/to/your-username.pem"
},
"ssl": {
"verify": false
}
}

Uploading Cookbooks

Cookbook Structure

my-cookbook/
├── metadata.rb
├── README.md
├── recipes/
│ └── default.rb
├── attributes/
│ └── default.rb
├── templates/
└── test/

metadata.rb

name 'my-cookbook'
maintainer 'Your Company'
maintainer_email 'chef@example.com'
license 'Apache-2.0'
description 'Installs/Configures my-cookbook'
version '1.0.0'
depends 'apt', '~> 7.0'
depends 'nginx', '>= 8.0'

Upload with Knife

Terminal window
# Upload single cookbook
knife cookbook upload my-cookbook
# Upload cookbook with dependencies
knife cookbook upload my-cookbook --include-dependencies
# Upload all cookbooks
knife cookbook upload --all

Upload with Berkshelf

Terminal window
# Install dependencies
berks install
# Upload to Chef Server
berks upload

Installing Cookbooks

With Knife

Terminal window
# Download cookbook
knife cookbook download my-cookbook 1.0.0
# List cookbooks
knife cookbook list

With Berkshelf

Create Berksfile:

source 'http://localhost:8080/chef/supermarket'
metadata
cookbook 'my-cookbook', '~> 1.0.0'
cookbook 'nginx', '>= 8.0'

Install:

Terminal window
berks install

Puppet

Endpoint

Puppet operations use the /puppet/{repo} endpoint:

http://localhost:8080/puppet/{repo}

Key: puppet

Clients

Compatible with:

  • puppet module - Puppet module management

Module Repository Configuration

puppet.conf

Add to puppet.conf:

[main]
module_repository = http://localhost:8080/puppet/modules

Command-Line Override

Terminal window
puppet module install mycompany-apache \
--module_repository=http://localhost:8080/puppet/modules

Publishing Modules

Module Structure

puppet-apache/
├── metadata.json
├── README.md
├── manifests/
│ └── init.pp
├── files/
├── templates/
├── lib/
└── spec/

metadata.json

{
"name": "mycompany-apache",
"version": "1.0.0",
"author": "Your Company",
"summary": "Apache HTTP Server module",
"license": "Apache-2.0",
"source": "https://github.com/mycompany/puppet-apache",
"project_page": "https://github.com/mycompany/puppet-apache",
"dependencies": [
{
"name": "puppetlabs/stdlib",
"version_requirement": ">= 4.0.0 < 9.0.0"
}
],
"operatingsystem_support": [
{
"operatingsystem": "Ubuntu",
"operatingsystemrelease": ["18.04", "20.04"]
}
]
}

Build and Publish

Terminal window
# Build module package
puppet module build
# This creates pkg/mycompany-apache-1.0.0.tar.gz
# Upload to registry
curl -X PUT \
-H "Authorization: Bearer your-token" \
-F "file=@pkg/mycompany-apache-1.0.0.tar.gz" \
http://localhost:8080/puppet/modules/mycompany-apache-1.0.0.tar.gz

Installing Modules

Terminal window
# Install latest version
puppet module install mycompany-apache
# Install specific version
puppet module install mycompany-apache --version 1.0.0
# Install with dependencies
puppet module install mycompany-apache --ignore-dependencies=false

Puppetfile

For r10k or Librarian-Puppet:

forge 'http://localhost:8080/puppet/modules'
mod 'mycompany-apache', '1.0.0'
mod 'puppetlabs-stdlib', '>= 4.0.0'

Ansible

Endpoint

Ansible operations use the /ansible/{repo} endpoint:

http://localhost:8080/ansible/{repo}

Key: ansible

Clients

Compatible with:

  • ansible-galaxy - Ansible content manager

Galaxy Server Configuration

ansible.cfg

Create or edit ansible.cfg:

[galaxy]
server_list = artifact_keeper
[galaxy_server.artifact_keeper]
url=http://localhost:8080/ansible/galaxy/
token=your-api-token

Environment Variable

Terminal window
export ANSIBLE_GALAXY_SERVER_LIST=artifact_keeper
export ANSIBLE_GALAXY_SERVER_ARTIFACT_KEEPER_URL=http://localhost:8080/ansible/galaxy/
export ANSIBLE_GALAXY_SERVER_ARTIFACT_KEEPER_TOKEN=your-api-token

Publishing Collections

Collection Structure

my_namespace.my_collection/
├── galaxy.yml
├── README.md
├── plugins/
│ ├── modules/
│ ├── inventory/
│ └── filter/
├── roles/
│ └── my_role/
└── docs/

galaxy.yml

namespace: my_namespace
name: my_collection
version: 1.0.0
readme: README.md
authors:
- Your Name <you@example.com>
description: My awesome Ansible collection
license:
- MIT
tags:
- automation
- infrastructure
dependencies:
ansible.posix: ">=1.0.0"
community.general: ">=3.0.0"
repository: https://github.com/mycompany/my_collection
documentation: https://docs.example.com/my_collection
homepage: https://example.com/my_collection
issues: https://github.com/mycompany/my_collection/issues

Build Collection

Terminal window
# Build collection tarball
ansible-galaxy collection build
# This creates my_namespace-my_collection-1.0.0.tar.gz

Publish Collection

Terminal window
# Publish to Artifact Keeper
ansible-galaxy collection publish \
my_namespace-my_collection-1.0.0.tar.gz \
--server artifact_keeper

Publishing Roles

Role Structure

my-role/
├── meta/
│ └── main.yml
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
├── files/
├── vars/
│ └── main.yml
├── defaults/
│ └── main.yml
└── README.md

meta/main.yml

galaxy_info:
author: Your Name
description: My awesome role
company: Your Company
license: MIT
min_ansible_version: "2.9"
platforms:
- name: Ubuntu
versions:
- focal
- jammy
galaxy_tags:
- web
- nginx
dependencies:
- role: geerlingguy.apache
version: "3.0.0"

Import Role

Terminal window
# Import from Git
ansible-galaxy role import \
--server artifact_keeper \
github_user repo_name

Installing Collections

Terminal window
# Install collection
ansible-galaxy collection install my_namespace.my_collection
# Install specific version
ansible-galaxy collection install my_namespace.my_collection:1.0.0
# Install from requirements file
ansible-galaxy collection install -r requirements.yml

requirements.yml

collections:
- name: my_namespace.my_collection
version: ">=1.0.0"
source: http://localhost:8080/ansible/galaxy/
- name: ansible.posix
version: "1.5.1"

Installing Roles

Terminal window
# Install role
ansible-galaxy role install my_namespace.my_role
# Install from requirements
ansible-galaxy role install -r requirements.yml

requirements.yml for Roles

roles:
- name: my_namespace.my_role
version: "1.0.0"
src: http://localhost:8080/ansible/galaxy/
- name: geerlingguy.apache
version: "3.0.0"

CI/CD Integration

Terraform in GitHub Actions

name: Terraform Module
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Package module
run: |
tar -czf module.tar.gz -C module .
- name: Publish to Artifact Keeper
run: |
curl -X PUT \
-H "Authorization: Bearer ${{ secrets.TERRAFORM_TOKEN }}" \
-F "file=@module.tar.gz" \
http://registry.example.com/terraform/modules/mycompany/vpc/aws/${GITHUB_REF#refs/tags/v}

Chef in GitLab CI

publish_cookbook:
image: chef/chefworkstation:latest
stage: deploy
script:
- knife cookbook upload my-cookbook --force
only:
- tags

Ansible in Jenkins

pipeline {
agent any
stages {
stage('Publish Collection') {
steps {
sh '''
ansible-galaxy collection build
ansible-galaxy collection publish \
*.tar.gz \
--server artifact_keeper \
--token $ANSIBLE_GALAXY_TOKEN
'''
}
}
}
}

Troubleshooting

Terraform Module Not Found

Verify module source format:

Terminal window
# List available modules
curl http://localhost:8080/terraform/modules/

Check Terraform configuration:

Terminal window
terraform init -upgrade

Vagrant Box Download Fails

Check box URL in Vagrantfile:

Terminal window
# Test box metadata
curl http://localhost:8080/vagrant/boxes/mycompany/ubuntu.json

Verify box exists:

Terminal window
vagrant box list

Chef Upload Authentication Error

Verify credentials:

Terminal window
knife client list

Test connection:

Terminal window
knife ssl check

Puppet Module Installation Fails

Check module repository:

Terminal window
puppet module list --modulepath=/path/to/modules

Clear module cache:

Terminal window
rm -rf ~/.puppet/var/puppet-module/cache

Ansible Collection Not Found

List configured servers:

Terminal window
ansible-galaxy collection list

Verify server configuration:

Terminal window
ansible-galaxy collection list --server artifact_keeper

Clear cache:

Terminal window
rm -rf ~/.ansible/collections

Best Practices

Version Management

Follow semantic versioning for all package types:

  • Major (1.0.0 -> 2.0.0): Breaking changes
  • Minor (1.0.0 -> 1.1.0): New features, backward compatible
  • Patch (1.0.0 -> 1.0.1): Bug fixes

Documentation

Include comprehensive documentation:

  • README.md with usage examples
  • CHANGELOG.md with version history
  • LICENSE file
  • Examples directory with sample configurations

Testing

Test infrastructure code before publishing:

  • Terraform: terraform validate, terraform plan
  • Vagrant: Test box provisioning
  • Chef: kitchen test
  • Puppet: puppet parser validate, pdk test unit
  • Ansible: ansible-lint, molecule test

Metadata

Include complete metadata:

  • Author and maintainer information
  • Dependencies with version constraints
  • Supported platforms and versions
  • License information
  • Source repository and documentation links

See Also