Skip to content

Instantly share code, notes, and snippets.

@dangle
Created June 28, 2024 03:42
Show Gist options
  • Save dangle/3927a32013514c4b5ee07ad5a0618dda to your computer and use it in GitHub Desktop.
Save dangle/3927a32013514c4b5ee07ad5a0618dda to your computer and use it in GitHub Desktop.
Instructions for automatically logging into the Unraid web GUI after authentication with Authentik

Secure the Unraid GUI behind Authentik

Assumptions

  1. You are using forward authentication behind a reverse proxy
  2. The internal host for Unraid does not use HTTPS
  3. The only user allowed for the Unraid web GUI is root
  4. The password for Unraid is stored as a user attribute
    1. The attribute can come from a group to which the user belongs

Instructions

  1. In Authentik create a new Scope Mapping
    1. The Name can be whatever you would like
    2. The Scope name MUST be ak_proxy
    3. Copy the contents of unraid_scope_mapping.py into the Expression field
  2. Update the "Important Variables" section of the Expression field
    1. Set internal_host to the domain or IP address of your Unraid instance
      1. If the Unraid web GUI isn't using the default HTTP port, make sure you specify it
    2. Set external_host to your Unraid domain name
  3. Create a new Provider of type Proxy Provider named "Unraid"
    1. Set it to "Forward auth (single application)"
    2. Fill in the External host field to match the external host specified above
    3. Under Advanced protocol settings > Additional scopes make sure that you select the scope that you created in the first step
  4. Create a new Application and attach the Provider to the Application
  5. Attach the new Application to the Outpost of your choice
  6. Follow the Authentik instructions for setting up your reverse proxy using forward authentication
###############################################################################
##### Important Variables #####################################################
###############################################################################
# Set this to your internal Unraid domain or IP
# Include the port if necessary
internal_host = "unraid.internal"
# Set this to your external Unraid domain
external_host = "unraid.external"
# This is the attribute the password is stored in on the user
password_attribute = "unraid_password"
###############################################################################
import hashlib
# Check if the user has the password attribute
# My users inherit it from the group "Unraid Admins"
all_attributes = request.user.group_attributes()
if password_attribute not in all_attributes:
ak_logger.info(f"user does not have the {password_attribute} attribute")
return {}
# As far as I know, this is the only valid username for Unraid
unraid_username = "root"
# Get the Unraid password from the attributes
unraid_password = all_attributes[password_attribute]
# Build the URI for the internal Unraid login page
unraid_uri = f"http://{internal_host}/login"
# Login to Unraid
response = requests.post(
unraid_uri,
data={
"username": unraid_username,
"password": unraid_password,
},
allow_redirects=False, # It's important to not follow redirects
)
# Unraid returns a redirect to the main page when successful
if response.status_code not in (200, 302):
ak_logger.error(f"the request failed with: {response.text}")
return {}
# Look for the Unraid cookie
# The Unraid cookie format is "unraid_{md5(server_name)}" so we can't just copy
# it directly
for key, value in response.cookies.items():
if key.startswith("unraid_"):
# The session for the browser won't match the internal site, so we have
# to create a new key for our cookie
host_hash = hashlib.md5(external_host.encode()).hexdigest()
cookie = f"unraid_{host_hash}={value}; path=/; HttpOnly; SameSite=Lax"
# Add a header to set this new cookie in the response to the browser
return {
"ak_proxy": {
"user_attributes": {
"additionalHeaders": {
"Set-Cookie": cookie,
}
}
}
}
# Something went wrong if the login succeeded but the cookie is missing
ak_logger.error("cannot get unraid token")
return {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment