Hi I'm Ryan
Hi I'm Ryan

- I'm a community focused Dev from Brum currently working @ Bluetel (Where you are now!)
- I have a general interest in all things web.
- I love programming mascots.
Disclaimer
(This talk was written in a caffeine fueled haze over the last few days.
All aboard the low standards limbo!)
Agenda
- What is Terraform? (~5 minutes)
- A very quick introduction to golang (~2 minutes)
- How to put together a custom terraform provider (~10 minutes)
- Live demo (~10 minutes)
- Questions
To gauge the room 🌡️
Who has used here has some familiarity with Terraform?
(Or one of it's various forks)
What is Terraform?
"Infrastructure automation to provision and manage resources in any cloud or data center."













The simulation
We live in








The simulation
We live in

Our AI overlords









This concept broadly known as Infrastructure As Code




Terraform has a 63.6% percent market share
(Excluding other forks of terraform like open tofu)
[Firefly state of IAC 2024]
Why bother?
¯\_(ツ)_/¯




Super Important Business
Critical Server™


Super Important Business
Critical Server™
"Restructuring"


Super Important Business
Critical Server™




Super Important Business
Critical Server™
Years Pass...




Super Important Business
Critical Server™
Years Pass...





Super Important Business
Critical Server™
Years Pass...






Super Important Business
Critical Server™
Years Pass...










Super Important Business
Critical Sever™
[DO NOT TOUCH]










Super Important Business
Critical Sever™
[DO NOT TOUCH]










You

S̵̯͊u̸̠͑p̴̩̓ȇ̴̗r̴͓̈́ ̴̡͐Ḯ̴̮m̷̦̃p̵̩̆o̵̢̾r̵̳͑t̸̨̂á̶̮n̴̤͘t̷̩̏ ̵͕́B̸̰͋ų̵̏s̷̝̓i̴̦̽n̸̬̈ē̴̟s̸̮̒s̴̻̊
̷̤̊C̴̜͝r̷͍̐ĭ̸͈t̵̹͒i̵͎̓ç̸̓ã̴͙ḷ̸͆ ̵̮̊S̷̯͊e̴̠̍v̸̡̒e̶̞͒r̶̲̕™̷̠̓
̸̹͋
̴̡̎[̶̨́D̴̠̈́O̸̭͑ ̵̠̃N̴͈̂Ȍ̵̺T̸͖̓ ̵̮͘T̶̢̅O̷̤͂U̵͓̍C̴̭̍H̴͖͂]̷͔̌










You

S̵̯͊u̸̠͑p̴̩̓ȇ̴̗r̴͓̈́ ̴̡͐Ḯ̴̮m̷̦̃p̵̩̆o̵̢̾r̵̳͑t̸̨̂á̶̮n̴̤͘t̷̩̏ ̵͕́B̸̰͋ų̵̏s̷̝̓i̴̦̽n̸̬̈ē̴̟s̸̮̒s̴̻̊
̷̤̊C̴̜͝r̷͍̐ĭ̸͈t̵̹͒i̵͎̓ç̸̓ã̴͙ḷ̸͆ ̵̮̊S̷̯͊e̴̠̍v̸̡̒e̶̞͒r̶̲̕™̷̠̓
̸̹͋
̴̡̎[̶̨́D̴̠̈́O̸̭͑ ̵̠̃N̴͈̂Ȍ̵̺T̸͖̓ ̵̮͘T̶̢̅O̷̤͂U̵͓̍C̴̭̍H̴͖͂]̷͔̌











You






S̵̯͊u̸̠͑p̴̩̓ȇ̴̗r̴͓̈́ ̴̡͐Ḯ̴̮m̷̦̃p̵̩̆o̵̢̾r̵̳͑t̸̨̂á̶̮n̴̤͘t̷̩̏ ̵͕́B̸̰͋ų̵̏s̷̝̓i̴̦̽n̸̬̈ē̴̟s̸̮̒s̴̻̊
̷̤̊C̴̜͝r̷͍̐ĭ̸͈t̵̹͒i̵͎̓ç̸̓ã̴͙ḷ̸͆ ̵̮̊S̷̯͊e̴̠̍v̸̡̒e̶̞͒r̶̲̕™̷̠̓
̸̹͋
̴̡̎[̶̨́D̴̠̈́O̸̭͑ ̵̠̃N̴͈̂Ȍ̵̺T̸͖̓ ̵̮͘T̶̢̅O̷̤͂U̵͓̍C̴̭̍H̴͖͂]̷͔̌








You

New Super Duper
Critical Server
Destroy
Recreate


You
New Super Duper
Critical Server

Step By Step
Step By Step
Write 📖
Plan📝
Apply 🚀
Write 📖
Writing Terraform
Hashicorp Configuration Language 🎉
resource "some_resource" "some_block" {
some_config_block {
bla = "bla"
bla2 = 1337
bla3 = false
}
something = "something"
}
Writing Terraform
Hashicorp Configuration Language 🎉
resource "some_resource" "some_block" {
some_config_block {
bla = "bla"
bla2 = 1337
bla3 = false
}
something = "something"
}
Writing Terraform
resource "aws_instance" "some_server" {
instance_type = "t2.micro"
[...]
}

resource "aws_instance" "some_server" {
instance_type = "t2.micro"
[...]
}
resource "aws_instance" "some_server2" {
instance_type = "t2.micro"
[...]
}


resource "aws_ami" "some_ami" {
prefix = "someing/*"
}
resource "aws_instance" "some_server" {
ami = aws_ami.some_ami
instance_type = "t2.micro"
[...]
}
resource "aws_instance" "some_server2" {
ami = aws_ami.some_ami
instance_type = "t2.micro"
[...]
}


AMI
Step By Step
Write 📖
Plan📝
Apply 🚀
Plan 📖
Plan 📖
Terraform State
(What Terraform thinks you currently have)


Code Changes
(What you are declaring the next state of the system should be)
Compute
Difference
Plan 📖
terraform plan -out "tfplan"
aws.region: Reading...
aws.region: Read complete after 0s [id=us-east-1]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
- resource "region" "us-east-1" {
- # The literal entire AWS Region
- }
Plan: 0 to add, 0 to change, 1 to destroy.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Saved the plan to: tfplan
To perform exactly these actions, run the following command to apply:
terraform apply "tfplan"
Step By Step
Write 📖
Plan📝
Apply 🚀
Apply 🚀
Apply 🚀
$ terraform apply
Enter a value: yes
Creating... module.crowdsrike_channel_file[291]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
update-status = "¯\_(ツ)_/¯"
Terraform Providers
[STUFF]




Provider

Terraform Providers
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
Terraform Providers

Terraform Providers



Custom Terra

form providers
Custom Terra

form providers

Custom Terra
form providers

Custom Terra
form providers

gRPC
Custom Provider
[Golang]

Custom Terra
form providers

gRPC
Custom Provider
Custom Provider
[Golang]

Custom Terra
form providers

gRPC
Custom Provider
Custom Provider
[Golang]

Custom Terra
form providers

gRPC
Custom Provider
Custom Terra
form providers

gRPC
Custom Provider
[Some other
Language]
(You monster)

Custom Terra
form providers

gRPC
Custom Provider
[Some other
Language]
(You monster)


Custom Terra
form providers

gRPC
Custom Provider
[Some other
Language]
(You monster)


Custom Terra
form providers

gRPC
Custom Provider
[Some other
Language]
(You monster)


Custom Terra
form providers
"There has been a lot of interest in writing providers using languages other than Go, and people frequently ask for information on how to go about doing that. The Terraform team's policy at this time is that while it is technically possible to write providers in languages other than Go, our tooling, documentation, and ecosystem will all assume your provider is being written in and distributed as Go code for the time being."
https://developer.hashicorp.com/terraform/plugin/best-practices/provider-code

Custom Terra
form providers
"If you are not using Go Lang Good Luck Have Fun, You are on your own"

Custom Terra
form providers
Lets go on a tangent
Custom Terra
form providers
Who here has used
Golang Before?
Custom Terra
form providers
package main
import "fmt"
func main() {
fmt.Println("Yam Orroight.")
}
Hello World
Custom Terra
form providers
package main
import "fmt"
func main() {
var number int = 0
yam := "yam"
fmt.Println(yam, "Orroight.")
}
Variables
Custom Terra
form providers
package main
import "fmt"
type MyStruct struct {
name string
number int
}
func NewMyStruct(name string, number int) *MyStruct {
return &MyStruct{
name: name,
number: number,
}
}
func main() {
myStruct := NewMyStruct("Jeff", 25)
fmt.Println(myStruct)
}
Structs
Custom Terra
form providers
package main
import "fmt"
type MyStruct struct {
name string
number int
}
func NewMyStruct(name string, number int) *MyStruct {
return &MyStruct{
name: name,
number: number,
}
}
// Value receiver method - doesn't modify the struct
func (m *MyStruct) GetInfo() string {
return fmt.Sprintf("Name: %s, Number: %d", m.name, m.number)
}
func main() {
myStruct := NewMyStruct("Jeff", 25)
// Using value receiver method
fmt.Println(myStruct.GetInfo()) // Name: Jeff, Number: 25
}
Methods
Custom Terra
form providers
More reading


Custom Terra
form providers
More reading


(https://gobyexample.com/)
Custom Terra
form providers
Writing custom providers
Custom Terra
form providers

Custom Terra
form providers
Terraform Providers
Custom Terra
form providers
"Providers are Terraform plugins that define resources and data sources for practitioners to use. Providers are wrapped by a provider server for interacting with Terraform."
- https://developer.hashicorp.com/terraform/plugin/framework/providers
Terraform Providers
Custom Terra
form providers
Terraform Custom Providers

Resource
Resource
Resource
Function
Data
Source
Custom Terra
form providers
Terraform Custom Providers

Resource
Resource
Resource
Function
Data
Source


Custom Terra
form providers

How providers work
Custom Terra
form providers

Custom Terra
form providers
terraform {
required_providers {
some_provider = {
source = "some/provider"
version = "0.0.1"
}
}
}
provider "some_provider" {
api_key = "foobar"
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
Terraform Resources
Custom Terra
form providers
resource "some_type" "some_id" {
name = "something"
attr = "value"
list_vals = [
1,
2,
3
]
}
Custom Terra
form providers
"Resources are an abstraction that allow Terraform to manage infrastructure objects, such as a compute instance, an access policy, or disk. Providers act as a translation layer between Terraform and an API, offering one or more resources for practitioners to define in a configuration."
- https://developer.hashicorp.com/terraform/plugin/framework
Custom Terra
form providers
A thing that you can:
- Create a new thing of
- Read the state of
- Update the state of
- Delete the thing from the system
Custom Terra
form providers
type Resource interface {
// Called when thing needs creating
Create(context.Context, CreateRequest, *CreateResponse)
// Called when thing needs reading
Read(context.Context, ReadRequest, *ReadResponse)
// Called when thing needs updating
Update(context.Context, UpdateRequest, *UpdateResponse)
// Called when thing needs deleting
Delete(context.Context, DeleteRequest, *DeleteResponse)
[...]
}
Custom Terra
form providers
Terraform Resources
type Resource interface {
// Called when thing needs creating
Create(context.Context, CreateRequest, *CreateResponse)
// Called when thing needs reading
Read(context.Context, ReadRequest, *ReadResponse)
// Called when thing needs updating
Update(context.Context, UpdateRequest, *UpdateResponse)
// Called when thing needs deleting
Delete(context.Context, DeleteRequest, *DeleteResponse)
// Called to get properites the resource block should have
// and it's behaviours
Schema(context.Context, SchemaRequest, *SchemaResponse)
// The name of the thing!
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// More functionality is available in extra methods
[...]
}
Custom Terra
form providers
Terraform Resources
type Resource interface {
// Called when thing needs creating
Create(context.Context, CreateRequest, *CreateResponse)
// Called when thing needs reading
Read(context.Context, ReadRequest, *ReadResponse)
// Called when thing needs updating
Update(context.Context, UpdateRequest, *UpdateResponse)
// Called when thing needs deleting
Delete(context.Context, DeleteRequest, *DeleteResponse)
// Called to get properites the resource block should have
// and it's behaviours
Schema(context.Context, SchemaRequest, *SchemaResponse)
// The name of the thing!
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// More functionality is available in extra methods
[...]
}
Custom Terra
form providers
Terraform Data Sources
Custom Terra
form providers
data "data_type" "name" {
attr = "value"
}
// Use data elsewhere in tf file
Custom Terra
form providers
"Data sources are an abstraction that allow Terraform to reference external data. Unlike managed resources, Terraform does not manage the lifecycle of the resource or data. Data sources are intended to have no side-effects."
- https://developer.hashicorp.com/terraform/plugin/framework/data-sources
Custom Terra
form providers
Custom Terra
form providers
type DataSource interface {
// Name of the datasource block
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// The structure of the data source
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Run when the data source needs refetching
Read(context.Context, ReadRequest, *ReadResponse)
}
Custom Terra
form providers
type DataSource interface {
Metadata([...])
Schema([...])
Read([...])
}
type Resource interface {
Create([...])
Read([...])
Update([...])
Delete([...])
Schema([...])
Metadata([...])
[...]
}
Custom Terra
form providers
type DataSource interface {
Metadata([...])
Schema([...])
Read([...])
}
type Resource interface {
Create([...])
Read([...])
Update([...])
Delete([...])
Schema([...])
Metadata([...])
[...]
}
Data sources act in a similar capacity to a "Read-Only" resource
Custom Terra
form providers
Functions
"Functions are an abstraction that allow providers to expose computational logic beyond Terraform's built-in functions and simplify practitioner configurations"
- https://developer.hashicorp.com/terraform/plugin/framework/functions

Function.
It's a function
Custom Terra
form providers
locals {
two = provider::provider_name::add(1, 1)
}
Custom Terra
form providers
type Function interface {
// The name of the function
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Defines the arguments it accept's and it's return values
Definition(context.Context, DefinitionRequest, *DefinitionResponse)
// The code to execute when the function it run
Run(context.Context, RunRequest, *RunResponse)
}
Custom Terra
form providers
Schemas
Custom Terra
form providers
func (d *LightDataSource) Schema(
_ context.Context,
req datasource.SchemaRequest,
resp *datasource.SchemaResponse
) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
"value": schema.StringAttribute{
Required: true,
},
"some_other_value": schema.BoolAttribute{
Optional: true
},
},
}
}
Custom Terra
form providers
func (d *LightDataSource) Schema(
_ context.Context,
req datasource.SchemaRequest,
resp *datasource.SchemaResponse
) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
"value": schema.StringAttribute{
Required: true,
},
"some_other_value": schema.BoolAttribute{
Optional: true
},
},
}
}
datasource "some_name" "some_value" {
value = "huh"
some_other_value = "yay"
}
Custom Terra
form providers
Configuring Clients
Custom Terra
form providers

Custom Terra
form providers

Live Demo

Custom Terra
form providers
Live Demo

Custom Terra
form providers
Further Reading

https://developer.hashicorp.com/terraform/plugin/framework
Custom Terra
form providers

Provider Testing
Advanced Use Cases for Resources (Import)
Provider Documentation Generation
Much much more!
Provider Registry Publishing
What we have covered in this talk
Custom Terra
form providers
Credits
Wikimedia [CC0, CC-SA4]
@_Iroshi (Gophers CC0)
Custom Terra
form providers
Questions?
Custom Terra
form providers
Thank you!
You can find my socials on
https//ryan.gd
Hashicorp User Group 2025
By Rizza
Hashicorp User Group 2025
- 54