Skip to content

Instantly share code, notes, and snippets.

@Syraxius
Last active May 16, 2017 12:11
Show Gist options
  • Save Syraxius/53e0caafd198e87b736709eecb6e388f to your computer and use it in GitHub Desktop.
Save Syraxius/53e0caafd198e87b736709eecb6e388f to your computer and use it in GitHub Desktop.
Set up oauth2_proxy (Google Oauth2 Provider), rundeckd and nginx
# Set the right server name in this file
# /etc/rundeck/framework.properties
# framework.properties -
#
# ----------------------------------------------------------------
# Rundeck server connection information
# ----------------------------------------------------------------
framework.server.name = rundeck.example.com
framework.server.hostname = rundeck.example.com
framework.server.port = 4440
framework.server.url = http://rundeck.example.com
# ----------------------------------------------------------------
# Installation locations
# ----------------------------------------------------------------
rdeck.base=/var/lib/rundeck
framework.projects.dir=/var/rundeck/projects
framework.etc.dir=/etc/rundeck
framework.var.dir=/var/lib/rundeck/var
framework.tmp.dir=/var/lib/rundeck/var/tmp
framework.logs.dir=/var/lib/rundeck/logs
framework.libext.dir=/var/lib/rundeck/libext
# ----------------------------------------------------------------
# SSH defaults for node executor and file copier
# ----------------------------------------------------------------
framework.ssh.keypath = /var/lib/rundeck/.ssh/id_rsa
framework.ssh.user = rundeck
# ssh connection timeout after a specified number of milliseconds.
# "0" value means wait forever.
framework.ssh.timeout = 0
# ----------------------------------------------------------------
# Auto generated server UUID:
# ----------------------------------------------------------------
rundeck.server.uuid = your-uuid-here
# Add the client ID and secret and a cookie secret in this file.
# /etc/oauth2_proxy.cfg
## OAuth2 Proxy Config File
## https://github.com/bitly/oauth2_proxy
## <addr>:<port> to listen on for HTTP/HTTPS clients
http_address = "0.0.0.0:4180"
# https_address = ":443"
## TLS Settings
# tls_cert_file = ""
# tls_key_file = ""
## the OAuth Redirect URL.
# defaults to the "https://" + requested host header + "/oauth2/callback"
redirect_url = "http://rundeck.example.com/oauth2/callback"
## the http url(s) of the upstream endpoint. If multiple, routing is based on path
upstreams = [
"http://localhost:4440/"
]
## Log requests to stdout
# request_logging = true
## pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream
# pass_basic_auth = true
# pass_user_headers = true
## pass the request Host Header to upstream
## when disabled the upstream Host is used as the Host Header
pass_host_header = true
## Email Domains to allow authentication for (this authorizes any email on this domain)
## for more granular authorization use `authenticated_emails_file`
## To authorize any email addresses use "*"
email_domains = [
"*"
]
## The OAuth Client ID, Secret
client_id = "PUT YOUR CLIENT_ID HERE"
client_secret = "PUT YOUR CLIENT_SECRET HERE"
## Pass OAuth Access token to upstream via "X-Forwarded-Access-Token"
pass_access_token = true
pass_roles_header = true
pass_user_id = true
## Authenticated Email Addresses File (one email per line)
# authenticated_emails_file = ""
## Htpasswd File (optional)
## Additionally authenticate against a htpasswd file. Entries must be created with "htpasswd -s" for SHA encryption
## enabling exposes a username/login signin form
# htpasswd_file = ""
## Templates
## optional directory with custom sign_in.html and error.html
# custom_templates_dir = ""
## skip SSL checking for HTTPS requests
# ssl_insecure_skip_verify = false
## Cookie Settings
## Name - the cookie name
## Secret - the seed string for secure cookies; should be 16, 24, or 32 bytes
## for use with an AES cipher when cookie_refresh or pass_access_token
## is set
## Domain - (optional) cookie domain to force cookies to (ie: .yourcompany.com)
## Expire - (duration) expire timeframe for cookie
## Refresh - (duration) refresh the cookie when duration has elapsed after cookie was initially set.
## Should be less than cookie_expire; set to 0 to disable.
## On refresh, OAuth token is re-validated.
## (ie: 1h means tokens are refreshed on request 1hr+ after it was set)
## Secure - secure cookies are only sent by the browser of a HTTPS connection (recommended)
## HttpOnly - httponly cookies are not readable by javascript (recommended)
cookie_name = "_oauth2_proxy"
cookie_secret = "TYPE AN APPROPRIATE SECRET HERE. SEE ABOVE"
cookie_domain = "rundeck.example.com"
# cookie_expire = "168h"
# cookie_refresh = ""
cookie_secure = false
# cookie_httponly = true
# Upstart script. Use if needed.
# /etc/init/oauth2_proxy.conf
description "Bit.ly Oauth2 Proxy"
start on (local-filesystems and net-device-up IFACE!=lo)
stop on runlevel [016]
setuid www-data
setgid www-data
respawn
respawn limit 10 5
exec /opt/oauth2_proxy/oauth2_proxy -config=/etc/oauth2_proxy.cfg
# Systemd script. Use if needed.
# /usr/lib/systemd/system/oauth2_proxy.service
[Unit]
Description=Bit.ly OAuth2 Proxy
[Service]
User=www-data
Group=www-data
ExecStart=/opt/oauth2_proxy/oauth2_proxy -config=/etc/oauth2_proxy.cfg
[Install]
WantedBy=multi-user.target
# Just pass any traffic to the oauth2_proxy server
# /etc/nginx/sites-enabled/rundeck
server {
listen 80;
server_name rundeck.example.com
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Roles admin;
location / {
proxy_pass http://localhost:4180;
}
}
# Add the preauthentication mode stuff in this file
# /etc/rundeck/rundeck-config.properties
#loglevel.default is the default log level for jobs: ERROR,WARN,INFO,VERBOSE,DEBUG
loglevel.default=INFO
rdeck.base=/var/lib/rundeck
#rss.enabled if set to true enables RSS feeds that are public (non-authenticated)
rss.enabled=false
# change hostname here
grails.serverURL=http://rundeck.example.com
dataSource.dbCreate = update
dataSource.url = jdbc:h2:file:/var/lib/rundeck/data/rundeckdb;MVCC=true
# Pre Auth mode settings
rundeck.security.authorization.preauthenticated.enabled=true
rundeck.security.authorization.preauthenticated.attributeName=REMOTE_USER_GROUPS
rundeck.security.authorization.preauthenticated.delimiter=,
# Header from which to obtain user name
rundeck.security.authorization.preauthenticated.userNameHeader=X-Forwarded-User
# Header from which to obtain list of roles
rundeck.security.authorization.preauthenticated.userRolesHeader=X-Forwarded-Roles
# Redirect to upstream logout url
rundeck.security.authorization.preauthenticated.redirectLogout=true
rundeck.security.authorization.preauthenticated.redirectUrl=/oauth2/sign_in
<!-- Just remove the entire <auth-constraint>...</auth-constraint> element and its children in this file to skip authentication -->
<!-- /var/lib/rundeck/exp/webapp/WEB-INF/web.xml -->
<web-app xmlns="http://java.sun.com/xml/ns/javaee" metadata-complete="true" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<display-name>/rundeck-production-2.8.2</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>rundeck-production-2.8.2</param-value>
</context-param>
<context-param>
<param-name>sample</param-name>
<param-value>Sample Value</param-value>
</context-param>
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>com.dtolabs.rundeck.server.filters.AuthFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>AssetPipelineFilter</filter-name>
<filter-class>asset.pipeline.grails.AssetPipelineFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>instrumentedFilter</filter-name>
<filter-class>com.codahale.metrics.servlet.InstrumentedFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<security-role>
<role-name>user</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>Login</web-resource-name>
<url-pattern>/user/login</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>LoginError</web-resource-name>
<url-pattern>/user/error</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Logout</web-resource-name>
<url-pattern>/user/logout</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Loggedout</web-resource-name>
<url-pattern>/user/loggedout</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Images</web-resource-name>
<url-pattern>/images/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>CSS</web-resource-name>
<url-pattern>/css/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>JS</web-resource-name>
<url-pattern>/js/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Feed</web-resource-name>
<url-pattern>/feed/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Test</web-resource-name>
<url-pattern>/test/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Api</web-resource-name>
<url-pattern>/api/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Static</web-resource-name>
<url-pattern>/static/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Assets</web-resource-name>
<url-pattern>/assets/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Fonts</web-resource-name>
<url-pattern>/fonts/*</url-pattern>
</web-resource-collection>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>rundeckrealm</realm-name>
<form-login-config>
<form-login-page>/user/login</form-login-page>
<form-error-page>/user/error</form-error-page>
</form-login-config>
</login-config>
<filter>
<filter-name>charEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>characterEncodingFilter</param-value>
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter>
<filter-name>urlMapping</filter-name>
<filter-class>org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>hiddenHttpMethod</filter-name>
<filter-class>org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>grailsWebRequest</filter-name>
<filter-class>org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter>
<filter-name>grailsCacheFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>instrumentedFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>hiddenHttpMethod</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>AssetPipelineFilter</filter-name>
<url-pattern>/assets/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>grailsWebRequest</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>urlMapping</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>grailsCacheFilter</filter-name>
<url-pattern>*.dispatch</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.codehaus.groovy.grails.plugins.log4j.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>grails</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet>
<servlet-name>gsp</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>metrics-admin-servlet</servlet-name>
<servlet-class>org.grails.plugins.metricsweb.DisablingAdminServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>grails-errorhandler</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.servlet.ErrorHandlingServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gsp</servlet-name>
<url-pattern>*.gsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>metrics-admin-servlet</servlet-name>
<url-pattern>/metrics/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>grails-errorhandler</servlet-name>
<url-pattern>/grails-errorhandler</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>grails</servlet-name>
<url-pattern>*.dispatch</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.gsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>500</error-code>
<location>/grails-errorhandler</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/grails-errorhandler</location>
</error-page>
</web-app>
@Syraxius
Copy link
Author

Syraxius commented May 16, 2017

This lets you authenticate your users using Google as the Oauth2 provider, and automatically log them into Rundeck as admin.

Please modify instructions/files as appropriate.

Instructions tested on Ubuntu 14.04 and 16.04.

  1. Get your oauth2_proxy server binary here (you can download the prebuilt binary), or compile the custom version here if you want GitHub group to roles support.
  2. Put the binary in /opt/oauth2_proxy/
  3. Sign up for a Oauth client ID here. Copy the client ID and secret.
  4. Enter http://rundeck.example.com/oauth2/callback in the list of Authorized redirect URIs
  5. Add the /etc/oauth2_proxy.cfg file. Paste your client ID and secret in this file. Also, type an appropriate cookie secret.
  6. Add the Upstart / Systemd scripts from above as per your needs.
    a. If using Systemd: systemctl enable oauth2_proxy; systemctl start oauth2_proxy
    b. If using Upstart: service oauth2_proxy start
  7. Install nginx if it is not in your system: apt-get install nginx
  8. Add the rundeck sites-enabled file.
  9. Restart or reload nginx: service nginx restart
  10. Install the rundeck package if you haven't done so (get the latest version here and modify steps accordingly):
    wget http://dl.bintray.com/rundeck/rundeck-deb/rundeck-2.8.2-1-GA.deb
    dpkg -i rundeck-2.8.2-1-GA.deb
  11. Modify the /etc/rundeck/rundeck-config.properties file and add the preauthentication items.
  12. Modify the /etc/rundeck/framework.properties file and change the hostname appropriately.
  13. Modify the /var/lib/rundeck/exp/webapp/WEB-INF/web.xml file and delete the element
  14. Restart Rundeck: service rundeckd restart

You are done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment