And we have (Space)lift (off)!

pawelpiwosz

Paweł Piwosz

Posted on February 26, 2023

And we have (Space)lift (off)!

This time we will configure and run our first small template through Spacelift. Our first step will be to configure the connection between AWS and the service. I assume, that the Spacelift account is created and connected with GitHub.

In this short series we will learn how to configure, connect and start to use Spacelift.

First thing to do for each real developer is to switch the GUI to dark mode :D Go to your account settings on the bottom left corner of your screen and find the dark mode setting. Right, we are ready to go :)

AWS

Connect Spacelift with Cloud provider

To work with AWS we need to configure our connection to the vendor. The documentation provided by Spacelift is really rich and clear, however, I'd like to mention the security aspect. First way, the easier one, is to provide programmatically available user with role to assume. Is it a good solution? Well, good enough. However, I prefer to use another way, which also is provided by Spacelift - the OIDC connection. On the end of the day it does the same thing, but from the security standpoint - it is better.

OIDC needs some configuration (obviously) and part of it is a thumbprint. As I do this as a tutorial, not fully blown production ready stuff, I show you how to get this thumbprint using CLI approach.

First, let's collect url of our spacelift app. Simply, look on your browser :) In my case it it https://<subdomain>.app.spacelift.io/. We have it, so let's generate the thumbprint.

I use Ubuntu to get these information. In fact WSL2 on Windows :). Execute:

curl https://<subdomain>.app.spacelift.io/.well-known/openid-configuration|jq

Please note, I added jq on the end to have nicer output.

Find the line with jwks_uri. Copy from it the domain name only and use it in following command.

openssl s_client -servername <subdomain>.app.spacelift.io -showcerts -connect <subdomain>.app.spacelift.io:443

Ensure, you don't have https, etc. Just the domain.

Scroll the output and find the certificate. There will be something like

-----BEGIN CERTIFICATE-----
somestring
-----END CERTIFICATE-----
Enter fullscreen mode Exit fullscreen mode

Create a file (for example certificate.crt) and copy this whole part there.

Now we are ready to generate thumbprint

openssl x509 -in certificate.crt -fingerprint -sha1 -noout |tr -d :

As you can see I used the tr command with pipe to get rid of :. If you are not familiar with pipes and redirections in Linux, no worries, here is my lab about it.

The string in output is a part which we need to use to complete our configuration of OIDC.

We can do it with Terraform, of course. In fact, if you plan to use it in the real project, I strongly recommend to do it with IaC. However, now you know how to do it from CLI :)

Let's terraform it

You know what? Creating all these resources on AWS from GUI is so old-fashioned :) Let's have a small Terraform template for it! We need to create:

  • OIDC itself
  • IAM Role to assume by Spacelift
  • IAM Policy which describes what Spacelift can do.

First, let's create the file providers.tf with this content

terraform {

  required_version = ">=1.3"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

And we can forget about this file from now.

We know what is our thumbprint, so we can create first block in main.tf.

provider "aws" {
  default_tags {
    tags = {
      Environment = "Sandbox"
      Terraform   = "True"
      Repo        = "spacelift-prep"
      Project     = "Spacelift tutorial"
    }
  }
}

resource "aws_iam_openid_connect_provider" "spacelift" {
  url = "https://<subdomain>.app.spacelift.io"

  client_id_list = [
    "<subdomain>.app.spacelift.io",
  ]

  thumbprint_list = ["<thumbprint>"]
}
Enter fullscreen mode Exit fullscreen mode

Please note, we also have the provider defined here.

Now, it is time to define the IAM Role. Within this definition, we will ensure that the Role can be assumend by Spacelift only. We want to build the trusted relation between this entity and Spacelift to secure our connection as much as possible.

The Role and condition inside is described well in Spacelift's documentation, so, I will not go into details. I just explain a few parts.

First, we use Federated access and we use for it the OIDC we defined earlier.

Second, please note the Condition section of the Role. This makes the connection more secure by narrowing the entities which can use this role. We can create even more precise boundary, all is in documentation. However, this one is enough for us at this moment.

And here is the Terraform code for our Role

resource "aws_iam_role" "spacelift-role" {
  depends_on = [
    aws_iam_openid_connect_provider.spacelift
  ]

  name        = "spacelift-role"
  description = "Role to assume by spacelift"

  assume_role_policy = <<ROLE
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "${aws_iam_openid_connect_provider.spacelift.arn}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "<subdomain>.app.spacelift.io:aud": "<subdomain>.app.spacelift.io"
        }
      }
    }
  ]
}
ROLE
}
Enter fullscreen mode Exit fullscreen mode

You might ask, why do you use this old-fashioned way with <<ROLE?. Well, good question :) For two reasons. I learned Terraform this way and this approach helps me to better see where Role or Policy document ends. Quite handy, especially for long documents.

Ok, finally, we will create "very secure" Policy and we will attach Policy to the Role. Please have in mind, that the Policy should by tailored to needs, not open like here. We do it for demo purposes, so we can live with it now.

resource "aws_iam_policy" "spacelift-policy" {
  name = "spacelift-policy"

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": ["*"]
    }
  ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "spacelift-iam-attachment" {
  role       = aws_iam_role.spacelift-role.name
  policy_arn = aws_iam_policy.spacelift-policy.arn
}
Enter fullscreen mode Exit fullscreen mode

No magic here, I suppose.

Init

We have our template, we can execute it.

First, we need to initialize Terraform

terraform init

We can format and validate the template

terraform fmt

terraform validate

Well, I have to do one more thing. I use many AWS profiles, therefore I need to specify it. There are many ways to do so, I use the easier and less flexible one - I put it into template:

provider "aws" {
  profile = "demos"
Enter fullscreen mode Exit fullscreen mode

Please remember, this is for demo purposes only, so, no issue with it.

Execute Terraform

We can deploy our stack.

First, let's see if all is ok

terraform plan

If all went ok, you should see something like

Plan: 4 to add, 0 to change, 0 to destroy.

Ok, so let's rock!

terraform apply -auto-approve

This Apply complete! Resources: 4 added, 0 changed, 0 destroyed. means success.

But wait... What Role should I use later? We can go to the GUI and... NO!

Outputs

Let's create one more file, called outputs.tf and put there

output "IAM-Role-to-assume" {
  description = "IAM Role to assume by Spacelift"
  value       = aws_iam_role.spacelift-role.arn
}
Enter fullscreen mode Exit fullscreen mode

Now we can run terraform refresh and we already see the ARN of the Role. If this info is needed later, we can run terraform output.

Spacelift

Well, looks like this episode is more about Terraform than Spacelift :) It is important though, to have good connection created, so I believe this is not a big deal :)

Ok, let's do our work on Spacelift side!

Go to your dashboard, to the `Cloud integrations (bottom left of the screen)

Add integration

And configure your AWS integration accordingly.

Configure integration

And... Yes, that's it :)

Key takeways

For now, we know how to connect the dots. In the next episode we will learn what Spacelift is and how to start with it.

💖 💪 🙅 🚩
pawelpiwosz
Paweł Piwosz

Posted on February 26, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Look around the stack functionality
spacelift Look around the stack functionality

February 28, 2023

Workers pool
spacelift Workers pool

March 4, 2023

Drift detection
spacelift Drift detection

March 1, 2023

First configuration and execution
spacelift First configuration and execution

February 26, 2023

And we have (Space)lift (off)!
spacelift And we have (Space)lift (off)!

February 26, 2023