Create and Manage AWS IoT Certificates

The aws:iot/certificate:Certificate resource, part of the Pulumi AWS provider, manages X.509 certificates for AWS IoT device authentication. This guide focuses on three capabilities: AWS-generated certificates, CSR-based certificate creation, and registering existing certificates.

Certificates authenticate devices to IoT Core but don’t grant permissions; you must attach IoT policies separately. The examples are intentionally small. Combine them with IoT policies, thing registries, and your device provisioning workflow.

Generate a new certificate and key pair

IoT devices need X.509 certificates for mutual TLS authentication. When you don’t have existing certificates, AWS IoT generates both the certificate and private key.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const cert = new aws.iot.Certificate("cert", {active: true});
import pulumi
import pulumi_aws as aws

cert = aws.iot.Certificate("cert", active=True)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iot"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := iot.NewCertificate(ctx, "cert", &iot.CertificateArgs{
			Active: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var cert = new Aws.Iot.Certificate("cert", new()
    {
        Active = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iot.Certificate;
import com.pulumi.aws.iot.CertificateArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var cert = new Certificate("cert", CertificateArgs.builder()
            .active(true)
            .build());

    }
}
resources:
  cert:
    type: aws:iot:Certificate
    properties:
      active: true

When you omit both csr and certificatePem, AWS IoT creates a new certificate and key pair. The active property controls whether devices can use the certificate immediately. The privateKey output contains the generated private key, which you must securely store and distribute to your device.

Register a certificate from your own CSR

Organizations with existing PKI infrastructure often generate their own key pairs and CSRs, then have AWS IoT sign the CSR.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";

const cert = new aws.iot.Certificate("cert", {
    csr: std.file({
        input: "/my/csr.pem",
    }).then(invoke => invoke.result),
    active: true,
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std

cert = aws.iot.Certificate("cert",
    csr=std.file(input="/my/csr.pem").result,
    active=True)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iot"
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		invokeFile, err := std.File(ctx, &std.FileArgs{
			Input: "/my/csr.pem",
		}, nil)
		if err != nil {
			return err
		}
		_, err = iot.NewCertificate(ctx, "cert", &iot.CertificateArgs{
			Csr:    pulumi.String(invokeFile.Result),
			Active: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var cert = new Aws.Iot.Certificate("cert", new()
    {
        Csr = Std.File.Invoke(new()
        {
            Input = "/my/csr.pem",
        }).Apply(invoke => invoke.Result),
        Active = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iot.Certificate;
import com.pulumi.aws.iot.CertificateArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var cert = new Certificate("cert", CertificateArgs.builder()
            .csr(StdFunctions.file(FileArgs.builder()
                .input("/my/csr.pem")
                .build()).result())
            .active(true)
            .build());

    }
}
resources:
  cert:
    type: aws:iot:Certificate
    properties:
      csr:
        fn::invoke:
          function: std:file
          arguments:
            input: /my/csr.pem
          return: result
      active: true

The csr property accepts a certificate signing request, allowing you to control the private key while AWS IoT signs and issues the certificate. Your private key never leaves your infrastructure. The file function reads the CSR from disk at deployment time.

Register an existing certificate without a CA

Some deployments need to register certificates issued by external CAs or self-signed certificates, allowing devices with pre-provisioned certificates to connect.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";

const cert = new aws.iot.Certificate("cert", {
    certificatePem: std.file({
        input: "/my/cert.pem",
    }).then(invoke => invoke.result),
    active: true,
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std

cert = aws.iot.Certificate("cert",
    certificate_pem=std.file(input="/my/cert.pem").result,
    active=True)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/iot"
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		invokeFile, err := std.File(ctx, &std.FileArgs{
			Input: "/my/cert.pem",
		}, nil)
		if err != nil {
			return err
		}
		_, err = iot.NewCertificate(ctx, "cert", &iot.CertificateArgs{
			CertificatePem: pulumi.String(invokeFile.Result),
			Active:         pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var cert = new Aws.Iot.Certificate("cert", new()
    {
        CertificatePem = Std.File.Invoke(new()
        {
            Input = "/my/cert.pem",
        }).Apply(invoke => invoke.Result),
        Active = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.iot.Certificate;
import com.pulumi.aws.iot.CertificateArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var cert = new Certificate("cert", CertificateArgs.builder()
            .certificatePem(StdFunctions.file(FileArgs.builder()
                .input("/my/cert.pem")
                .build()).result())
            .active(true)
            .build());

    }
}
resources:
  cert:
    type: aws:iot:Certificate
    properties:
      certificatePem:
        fn::invoke:
          function: std:file
          arguments:
            input: /my/cert.pem
          return: result
      active: true

The certificatePem property registers an existing certificate without CA chain validation. This approach works when devices already have certificates and private keys from another source. The certificate is registered directly with AWS IoT Core.

Beyond these examples

These snippets focus on specific certificate features: certificate generation and registration, and CSR-based provisioning. They’re intentionally minimal rather than full device provisioning workflows.

The examples may reference pre-existing infrastructure such as certificate files on disk for CSR and existing certificate examples. They focus on certificate management rather than the complete IoT device lifecycle.

To keep things focused, common certificate patterns are omitted, including:

  • CA certificate registration (caPem property)
  • Certificate activation/deactivation lifecycle
  • IoT policy attachment for device permissions
  • Thing attachment for device registry integration

These omissions are intentional: the goal is to illustrate how each certificate feature is wired, not provide drop-in device provisioning modules. See the IoT Certificate resource reference for all available configuration options.

Let's create and Manage AWS IoT Certificates

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Certificate Creation & Modes
What are the different ways to create an IoT certificate?

You have three options:

  1. With CSR - Provide csr to generate a certificate from your certificate signing request
  2. Auto-generate - Omit both csr and certificatePem to generate both certificate and keys
  3. Existing certificate - Provide certificatePem to register an existing certificate
When do I get private and public keys as outputs?
The privateKey and publicKey outputs are only available when you auto-generate (omit both csr and certificatePem). If you provide a CSR or existing certificate, keys are not generated.
CA Certificates & Requirements
Can I use a CA certificate when registering my certificate?
Yes, specify caPem to register a certificate with a CA. However, the CA certificate must already be registered with AWS IoT before you create the certificate.
Configuration & Activation
What does the active property do?
The active property is a required boolean flag that controls whether the certificate is active and can be used for authentication. Set it to true to activate the certificate.
Immutability & Limitations
What properties can't I change after creating the certificate?
The certificatePem, caPem, and csr properties are immutable. Changing any of these requires replacing the certificate resource.

Using a different cloud?

Explore security guides for other cloud providers: