Terraform for Spotify

I recently discovered that a Terraform provider had recently been released for Spotify (see article). Being an avid music listener and a Terraform fan, I thought I’d give it a try.

I followed the Spotify tutorial on HashiCorp Learn. It had a couple of minor issues – which have already been reported – but I was able to create my playlist pretty easily.

This was my configuration file:

terraform {
  required_providers {
    spotify = {
      version = "~> 0.2.6"
      source  = "conradludgate/spotify"
    }
  }
}

variable "spotify_api_key" {
  type = string
}

provider "spotify" {
  api_key = var.spotify_api_key
}

resource "spotify_playlist" "playlist" {
  name        = "Terraform Summer Playlist"
  description = "This playlist was created by Terraform"
  public      = true

  tracks = [
    data.spotify_search_track.by_artist.tracks[0].id,
    data.spotify_search_track.by_artist.tracks[1].id,
    data.spotify_search_track.by_artist.tracks[2].id,
    data.spotify_search_track.by_artist.tracks[3].id,
    data.spotify_search_track.by_artist.tracks[4].id,
    data.spotify_search_track.by_artist.tracks[5].id,
    data.spotify_search_track.by_artist.tracks[6].id,
    data.spotify_search_track.by_artist.tracks[7].id,
  ]
}

data "spotify_search_track" "by_artist" {
  artist = "The Weeknd"

}
output "playlist_url" {
  value       = "https://open.spotify.com/playlist/${spotify_playlist.playlist.id}"
  description = "Visit this URL in your browser to listen to the playlist"
} 

It’s pretty self explanatory: it creates a playlist based on an artist’s name and its most popular tracks. As an output, it tells me the URL of the playlist.

Terraform Provider for Spotify

It worked pretty seamlessly and created a short playlist with the top songs of The Weeknd.

nicovibert % terraform apply  


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # spotify_playlist.playlist will be created
  + resource "spotify_playlist" "playlist" {
      + description = "This playlist was created by Terraform"
      + id          = (known after apply)
      + name        = "Terraform Summer Playlist"
      + public      = true
      + snapshot_id = (known after apply)
      + tracks      = [
          + "37BZB0z9T8Xu7U3e65qxFy",
          + "0VjIjW4GlUZAMYd2vXMi3b",
          + "6OGogr19zPTM4BALXuMQpF",
          + "5QO79kh1waicV47BqGRL3g",
          + "7fBv7CLKzipRk6EC6TWHOB",
          + "7MXVkk9YMctZqd1Srtv4MB",
          + "6M3PsepEj5gyJoIi7Xvr7u",
          + "22VdIZQfgXJea34mQxlt81",
        ]
    }

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

Changes to Outputs:
  + playlist_url = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

spotify_playlist.playlist: Creating...
spotify_playlist.playlist: Creation complete after 0s [id=6iqVu8UxIlyKwwefSX9Slt]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

playlist_url = "https://open.spotify.com/playlist/6iqVu8UxIlyKwwefSX9Slt"

To access your Spotify account over its APIs, you need an API token from from the Spotify Developer portal. The Developer Experience on Spotify is pretty impressive and I was able to quickly get my token and use the embedded API console to get data on artists or tracks.


But what if I have questionable music taste and I don’t want people to see my playlists? I could use policy-as-code to ensure my playlists stay private.

So I set up Terraform Cloud to check whether I could apply Sentinel policies to my playlist (I had initially run Terraform OSS locally but it does not support Sentinel so you need Terraform Cloud or Terraform Enterprise to enforce these security policies).

I use a simple policy like the one below – it lists all the playlists that the “public” attribute is set to “true” and would trigger a failed policy event during the execution of the Terraform code.

This type of policy is pretty common: it looks for a resource (line 14) named “spotify_playlist” from the output of Terraform Plan (line 6) and then we use a common function (filter_attribute_not_in_list) to look if an attribute is or is not in the list (line 20).

# Rule to prevent a user to create public Spotify playlist.

# Import common-functions/tfplan-functions/tfplan-functions.sentinel
# with alias "plan"

import "tfplan-functions" as plan

## Only private playlist are allowed
allowed_playlist_type = [false]

print(allowed_playlist_type)
# Get all playlist

allPlaylist = plan.find_resources("spotify_playlist")

print(allPlaylist)
# Filter to playlist with wrong settings
# Warnings will be printed for all violations.

wrongPlaylist = plan.filter_attribute_not_in_list(allPlaylist, "public", allowed_playlist_type, true)

print(wrongPlaylist)

main = rule {
 length(wrongPlaylist["messages"]) is 0
}

By default, when you run Terraform with remote plan, my Terraform configuration is created locally but Terraform is executed remotely and the Terraform backend is stored in the cloud. And my Sentinel policies check what I am trying to create or update and will alert me that everyone can see I have bizarre musical taste.

With a private playlist, the policy fails:

With a private playlist, the policy succeeds:

Note that to authenticate to Spotify, you need an oauth2 server running to act as some middleware. You can either run it locally on a Docker container or externally (which I needed to do once Terraform was executed remotely).

Go and check out the provider and give it a try!

Thanks for reading.

PS: in the next post, I will show you another example of a Sentinel policy with the Spotify provider and how you can write and test Sentinel policies.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s