<p>There are a few issues with this cloud-init script.</p>
<ul>
<li><code>#groups</code> is commented out, so the list beneath it makes it invalid YAML.</li>
<li>Even if we uncomment groups, <code>  - ubuntu: [root,sys]</code> is invalid because the default user already has a group specification. If you look near the bottom of <code>/etc/cloud/cloud.cfg</code> on a launched instance, you should see something like:</li>
</ul>
<pre class="lang-yaml prettyprint-override"><code>system_info:
   # This will affect which distro class gets used
   distro: ubuntu
   # Default user name + that default users groups (if added/used)
   default_user:
     name: ubuntu
     lock_passwd: True
     gecos: Ubuntu
     groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
     sudo: [&quot;ALL=(ALL) NOPASSWD:ALL&quot;]
     shell: /bin/bash
</code></pre>
<p>So you either need to remove the <code>ubuntu</code> line from your groups definition, or remove <code>- default</code> from your user definition and define the <code>ubuntu</code> user manually.</p>
<ul>
<li>Your ssh key is also pasted as invalid YAML. Keep it as a single line</li>
<li>In your runcmd, <code>sudo su</code> doesn't work that way in a script. Instead you should <code>sudo -u &lt;user&gt;</code> for an individual user to run an individual command. Additionally, <code>sudo</code> isn't needed for root permissions as all user scripts run as root already.</li>
</ul>
<p>Fixing all of these issues, we should get a resulting cloud-init script that looks something like this:</p>
<pre class="lang-yaml prettyprint-override"><code>#cloud-config

# Add the empty group hashicorp.
groups:
  - hashicorp

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: terraform
    gecos: terraform
    shell: /bin/bash
    primary_group: hashicorp
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    lock_passwd: false
    ssh_authorized_keys:
      - ssh rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMT6uYfhWx8jOmiGR9ryIPKcWy2ceqvyZ4Q4+q5QTiZtlbWxbP37YZnT8uQhyjB4QRR1cjOyvGKC3Zu0Isy0eHIx2lGm/7B04bsoWWAUqhJmYWMZlivnHtJJJ4P5gnvXiRNmFg9iK07C7ClggNBAQZZHUeA5wcnvvHT/pDkGUjMUqgLvmWRJqJM9qLT717e229F1Fyh+sYtAj08qmcFF1JCs2D33R46RQ8YBMpQqmWLfjuJDUrjdvMu7Mv3aPpaeUWuYoC90iHR9XMeNonrtRlx21nY3CoMZ0AOpeNl999UzyMJrsvN4qm6byK2Pc6jrEyKr9jI8SvMEGdSWgqr/Hd

# Downloads the golang package
packages:
  - golang-go

# Sets the GOPATH &amp; downloads the demo payload
runcmd:
  - mkdir /home/terraform/go
  - chown terraform:hashicorp /home/terraform/go
  - sudo GOPATH=/home/terraform/go -u terraform go install github.com/hashicorp/learn-go-webapp-demo@latest
</code></pre>

CC BY-SA 4.0
2022-04-26T16:54:03.550Z
I've used this cloud-init script, but I obtain the following error: Permission denied (publickey). I've ensured that I'm using the correct private key, in PEM format.
Huzi 
CC BY-SA 4.0
2022-04-27T18:05:41.500Z
I copied what you initially provided, but every public RSA key I've seen starts with `ssh-rsa` not `ssh rsa`. Ensure you've copied the key correctly.
falcojr
CC BY-SA 4.0
2022-04-25T14:38:34.163Z
2022-04-25T14:38:34.163Z
falcojr
<p>Maybe it does not matter but also try to add &quot;${}&quot; around terraform's file function before rendering:</p>
<pre><code>data &quot;template_file&quot; &quot;init_script&quot; {
  template = &quot;${file(&quot;../scripts/add-ssh-web-app.yaml&quot;)}&quot;
}
</code></pre>

CC BY-SA 4.0
2022-04-26T07:19:18.433Z
2022-04-26T07:19:18.433Z
Serve Laurijssen
<p>I am working through this Terraform <a href="https://learn.hashicorp.com/tutorials/terraform/cloud-init?in=terraform/provision" rel="nofollow noreferrer">tutorial</a>, which boots up a Go web app on an EC2 instance, using Terraform and cloud-init. This is my Terraform config file:</p>
<pre><code>terraform {
  required_version = &quot;&gt;= 0.13&quot;
  required_providers {
    aws = {
      source  = &quot;hashicorp/aws&quot;
      version = &quot;~&gt; 3.0&quot;
    }
  }
}


provider &quot;aws&quot; {
  region = var.region
}

data &quot;aws_ami&quot; &quot;ubuntu&quot; {
  most_recent = true

  filter {
    name   = &quot;name&quot;
    values = [&quot;ubuntu/images/hvm-ssd/ubuntu-*20*-amd64-server-*&quot;]
  }

  filter {
    name   = &quot;virtualization-type&quot;
    values = [&quot;hvm&quot;]
  }

  owners = [&quot;099720109477&quot;] # Canonical
}

resource &quot;aws_vpc&quot; &quot;vpc&quot; {
  cidr_block           = var.cidr_vpc
  enable_dns_support   = true
  enable_dns_hostnames = true
}

resource &quot;aws_internet_gateway&quot; &quot;igw&quot; {
  vpc_id = aws_vpc.vpc.id
}

resource &quot;aws_subnet&quot; &quot;subnet_public&quot; {
  vpc_id     = aws_vpc.vpc.id
  cidr_block = var.cidr_subnet
}

resource &quot;aws_route_table&quot; &quot;rtb_public&quot; {
  vpc_id = aws_vpc.vpc.id

  route {
    cidr_block = &quot;0.0.0.0/0&quot;
    gateway_id = aws_internet_gateway.igw.id
  }
}

resource &quot;aws_route_table_association&quot; &quot;rta_subnet_public&quot; {
  subnet_id      = aws_subnet.subnet_public.id
  route_table_id = aws_route_table.rtb_public.id
}

resource &quot;aws_security_group&quot; &quot;sg_22_80&quot; {
  name   = &quot;sg_22&quot;
  vpc_id = aws_vpc.vpc.id

  # SSH access from the VPC
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = &quot;tcp&quot;
    cidr_blocks = [&quot;0.0.0.0/0&quot;]
  }

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = &quot;tcp&quot;
    cidr_blocks = [&quot;0.0.0.0/0&quot;]
  }


  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = &quot;tcp&quot;
    cidr_blocks = [&quot;0.0.0.0/0&quot;]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = &quot;-1&quot;
    cidr_blocks = [&quot;0.0.0.0/0&quot;]
  }
}

data &quot;template_file&quot; &quot;user_data&quot; {
  template = file(&quot;../scripts/add-ssh-web-app.yaml&quot;)
}

resource &quot;aws_instance&quot; &quot;web&quot; {
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = &quot;t2.micro&quot;
  subnet_id                   = aws_subnet.subnet_public.id
  vpc_security_group_ids      = [aws_security_group.sg_22_80.id]
  associate_public_ip_address = true
  user_data                   = data.template_file.user_data.rendered

  tags = {
    Name = &quot;Learn-CloudInit&quot;
  }
}

output &quot;public_ip&quot; {
  value = aws_instance.web.public_ip
}
</code></pre>
<p>My cloud-init script looks like this:</p>
<pre><code>#cloud-config
# Add groups to the system
# Adds the ubuntu group with members 'root' and 'sys'
# and the empty group hashicorp.
#groups:
  - ubuntu: [root,sys]
  - hashicorp

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: terraform
    gecos: terraform
    shell: /bin/bash
    primary_group: hashicorp
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    lock_passwd: false
    ssh_authorized_keys:
      - ssh rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMT6uYfhWx8jOmiGR9ryIPKcWy2ceqvyZ4
Q4+q5QTiZtlbWxbP37YZnT8uQhyjB4QRR1cjOyvGKC3Zu0Isy0eHIx2lGm/7B04b
soWWAUqhJmYWMZlivnHtJJJ4P5gnvXiRNmFg9iK07C7ClggNBAQZZHUeA5wcnvvH
T/pDkGUjMUqgLvmWRJqJM9qLT717e229F1Fyh+sYtAj08qmcFF1JCs2D33R46RQ8
YBMpQqmWLfjuJDUrjdvMu7Mv3aPpaeUWuYoC90iHR9XMeNonrtRlx21nY3CoMZ0A
OpeNl999UzyMJrsvN4qm6byK2Pc6jrEyKr9jI8SvMEGdSWgqr/Hd



# Downloads the golang package
packages:
  - golang-go

# Sets the GOPATH &amp; downloads the demo payload
runcmd:
  - sudo su terraform
  - sudo mkdir /home/terraform/go
  - sudo chown terraform:hashicorp /home/terraform/go
  - export GOPATH=/home/terraform/go
  - go get github.com/hashicorp/learn-go-webapp-demo
</code></pre>
<p>After successfully applying the Terraform config, I obtain the following error when I try to SSH into this instance from the CLI using my OpenSSH private key:</p>
<p><em>Permission denied (publickey,gssapi-keyex,gssapi-with-mic).</em></p>
<p>To further investigate, I have SSH'd into the instance with AWS Direct Connect, from which I found none of the users, groups or directories had been created and the packages hadn't been installed - so it seems like the cloud-init script did not run at all. I'm guessing I can't SSH into my instance because the public key wasn't uploaded to it.</p>
<p>I assumed that this could be an issue with Ubuntu, so I changed the AMI to Linux 2, which resulted in the same error. Am I missing something obvious?</p>

CC BY-SA 4.0
2022-04-21T12:34:44.920Z
this may just be stackexchange formatting so I wouldn't want to consider this a real answer. It's pretty important that the public key is formatted correctly.  I think yaml will munge your rsa key together, but can you try just removing the newlines?
Peter Turner
<amazon-web-services><terraform><infrastructure-as-code><ssh><cloud-init>
Cloud-Init Script Won't Run?
Huzi 
# Cloud-Init Script Won't Run?

(Asked by: username_0 on 2022-04-21)

I am working through this Terraform tutorial, which boots up a Go web app on an EC2 instance, using Terraform and cloud-init. This is my Terraform config file:
terraform {
  required_version = ">= 0.13"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}


provider "aws" {
  region = var.region
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-*20*-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_vpc" "vpc" {
  cidr_block           = var.cidr_vpc
  enable_dns_support   = true
  enable_dns_hostnames = true
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
}

resource "aws_subnet" "subnet_public" {
  vpc_id     = aws_vpc.vpc.id
  cidr_block = var.cidr_subnet
}

resource "aws_route_table" "rtb_public" {
  vpc_id = aws_vpc.vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
}

resource "aws_route_table_association" "rta_subnet_public" {
  subnet_id      = aws_subnet.subnet_public.id
  route_table_id = aws_route_table.rtb_public.id
}

resource "aws_security_group" "sg_22_80" {
  name   = "sg_22"
  vpc_id = aws_vpc.vpc.id

  # SSH access from the VPC
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }


  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

data "template_file" "user_data" {
  template = file("../scripts/add-ssh-web-app.yaml")
}

resource "aws_instance" "web" {
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = "t2.micro"
  subnet_id                   = aws_subnet.subnet_public.id
  vpc_security_group_ids      = [aws_security_group.sg_22_80.id]
  associate_public_ip_address = true
  user_data                   = data.template_file.user_data.rendered

  tags = {
    Name = "Learn-CloudInit"
  }
}

output "public_ip" {
  value = aws_instance.web.public_ip
}

My cloud-init script looks like this:
#cloud-config
# Add groups to the system
# Adds the ubuntu group with members 'root' and 'sys'
# and the empty group hashicorp.
#groups:
  - ubuntu: [root,sys]
  - hashicorp

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: terraform
    gecos: terraform
    shell: /bin/bash
    primary_group: hashicorp
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    lock_passwd: false
    ssh_authorized_keys:
      - ssh rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMT6uYfhWx8jOmiGR9ryIPKcWy2ceqvyZ4
Q4+q5QTiZtlbWxbP37YZnT8uQhyjB4QRR1cjOyvGKC3Zu0Isy0eHIx2lGm/7B04b
soWWAUqhJmYWMZlivnHtJJJ4P5gnvXiRNmFg9iK07C7ClggNBAQZZHUeA5wcnvvH
T/pDkGUjMUqgLvmWRJqJM9qLT717e229F1Fyh+sYtAj08qmcFF1JCs2D33R46RQ8
YBMpQqmWLfjuJDUrjdvMu7Mv3aPpaeUWuYoC90iHR9XMeNonrtRlx21nY3CoMZ0A
OpeNl999UzyMJrsvN4qm6byK2Pc6jrEyKr9jI8SvMEGdSWgqr/Hd



# Downloads the golang package
packages:
  - golang-go

# Sets the GOPATH & downloads the demo payload
runcmd:
  - sudo su terraform
  - sudo mkdir /home/terraform/go
  - sudo chown terraform:hashicorp /home/terraform/go
  - export GOPATH=/home/terraform/go
  - go get github.com/hashicorp/learn-go-webapp-demo

After successfully applying the Terraform config, I obtain the following error when I try to SSH into this instance from the CLI using my OpenSSH private key:
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
To further investigate, I have SSH'd into the instance with AWS Direct Connect, from which I found none of the users, groups or directories had been created and the packages hadn't been installed - so it seems like the cloud-init script did not run at all. I'm guessing I can't SSH into my instance because the public key wasn't uploaded to it.
I assumed that this could be an issue with Ubuntu, so I changed the AMI to Linux 2, which resulted in the same error. Am I missing something obvious?

**Tags:** amazon-web-services, terraform, infrastructure-as-code, ssh, cloud-init

> **Comments:**
> **username_1**: this may just be stackexchange formatting so I wouldn't want to consider this a real answer. It's pretty important that the public key is formatted correctly.  I think yaml will munge your rsa key together, but can you try just removing the newlines?  

---

## 2 answers

### Answer by username_2 on 2022-04-25. Score: 3

There are a few issues with this cloud-init script.

#groups is commented out, so the list beneath it makes it invalid YAML.
Even if we uncomment groups,   - ubuntu: [root,sys] is invalid because the default user already has a group specification. If you look near the bottom of /etc/cloud/cloud.cfg on a launched instance, you should see something like:

system_info:
   # This will affect which distro class gets used
   distro: ubuntu
   # Default user name + that default users groups (if added/used)
   default_user:
     name: ubuntu
     lock_passwd: True
     gecos: Ubuntu
     groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
     sudo: ["ALL=(ALL) NOPASSWD:ALL"]
     shell: /bin/bash

So you either need to remove the ubuntu line from your groups definition, or remove - default from your user definition and define the ubuntu user manually.

Your ssh key is also pasted as invalid YAML. Keep it as a single line
In your runcmd, sudo su doesn't work that way in a script. Instead you should sudo -u  for an individual user to run an individual command. Additionally, sudo isn't needed for root permissions as all user scripts run as root already.

Fixing all of these issues, we should get a resulting cloud-init script that looks something like this:
#cloud-config

# Add the empty group hashicorp.
groups:
  - hashicorp

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: terraform
    gecos: terraform
    shell: /bin/bash
    primary_group: hashicorp
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    lock_passwd: false
    ssh_authorized_keys:
      - ssh rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMT6uYfhWx8jOmiGR9ryIPKcWy2ceqvyZ4Q4+q5QTiZtlbWxbP37YZnT8uQhyjB4QRR1cjOyvGKC3Zu0Isy0eHIx2lGm/7B04bsoWWAUqhJmYWMZlivnHtJJJ4P5gnvXiRNmFg9iK07C7ClggNBAQZZHUeA5wcnvvHT/pDkGUjMUqgLvmWRJqJM9qLT717e229F1Fyh+sYtAj08qmcFF1JCs2D33R46RQ8YBMpQqmWLfjuJDUrjdvMu7Mv3aPpaeUWuYoC90iHR9XMeNonrtRlx21nY3CoMZ0AOpeNl999UzyMJrsvN4qm6byK2Pc6jrEyKr9jI8SvMEGdSWgqr/Hd

# Downloads the golang package
packages:
  - golang-go

# Sets the GOPATH & downloads the demo payload
runcmd:
  - mkdir /home/terraform/go
  - chown terraform:hashicorp /home/terraform/go
  - sudo GOPATH=/home/terraform/go -u terraform go install github.com/hashicorp/learn-go-webapp-demo@latest

> **Comments:**
> **username_0**: I've used this cloud-init script, but I obtain the following error: Permission denied (publickey). I've ensured that I'm using the correct private key, in PEM format.  
> **username_2**: I copied what you initially provided, but every public RSA key I've seen starts with `ssh-rsa` not `ssh rsa`. Ensure you've copied the key correctly.  

---

### Answer by username_3 on 2022-04-26. Score: 0

Maybe it does not matter but also try to add "${}" around terraform's file function before rendering:
data "template_file" "init_script" {
  template = "${file("../scripts/add-ssh-web-app.yaml")}"
}


---

