Category: Uncategorized

  • PowerShell script to find users with OWA and Mobile App enabled – Office 365

    I was tasked to create a PowerShell script to quickly find out how many users have OWA enabled and how many have Mobile App (ActiveSync) enabled. Complicating this was the deployment is on Office 365/Exchange 365 setup. Following is the end result of the endeavor which will quickly give you the list you want.

    # Created by Asanka Gunasekara - 2/14/2020
    # This script generates list of users who has OWA enabled and Mobile/Active Sync Enabled.
    # User needs special permission: https://docs.microsoft.com/en-us/exchange/troubleshoot/connecting-to-the-service/access-denied-connect-powershell
    # User needs to enter their full username: [email protected]
    
    $UserCredential = Get-Credential
    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
    Import-PSSession $Session -DisableNameChecking
    
    Write-Output ""
    Write-Output "Users with OWA Enabled"
    Get-CASMailbox -ResultSize Unlimited | where { $_.OWAEnabled } | sort DisplayName | ft DisplayName, PrimarySmtpAddress, OWAEnabled –autosize
    Write-Output "Users with Mobile APP Enabled"
    Get-CASMailbox -ResultSize Unlimited | where { $_.ActiveSyncEnabled} | sort DisplayName | ft DisplayName, PrimarySmtpAddress, activesyncenabled –autosize
    
    Remove-PSSession $Session
  • Traditional Reverse Proxy with Traefik

    So the other day I needed to setup a reverse proxy server for a client of mine who wanted some internal servers accessible from the internet. I tested this with nginx but had issues with LetsEncrypt as well as some pages timing out.

    I finally ended up with Traefik but boy did it take along time to get it configured as I was not familiar with Docker and most guides are Docker with other Docker Containers.

    Following the guide below will get you up and running in no time with

    • Integrated LetsEncrypt SSL certificates, which will auto generate and renew.
    • Standalone systemd service for ease of use/management
    • A hardened/restricted Traefik service for added security.

    This guide assumes the following has already been done:

    • Latest Debian/Ubuntu server has been installed/setup.
    • No other services are using ports 80/443
    • If server is behind NAT, ports 80 and 443 has been forwarded correctly.
    • DNS records have been correctly updated to point to Traefic Server.

    Let’s start with setting up the working directories and files required to run Traefik and grabbing the Traefik binary.

    mkdir /etc/traefik
    touch /etc/traefik/traefik.toml
    touch /etc/traefik/acme.json
    chmod 0600 /etc/traefik/acme.json
    wget https://github.com/containous/traefik/releases/download/v1.7.9/traefik
    chmod +x traefik
    mv traefik /usr/local/bin/

    Next, we need to edit traefik.toml which holds configuration for Traefik. In the following sample configuration, it is configured to

    • Listen on HTTP and HTTPS (80/443)
    • Redirect HTTP to HTTPS
    • Enabled LetsEncrypt integration
    • Created 2x backend services (Plex and ERPNext)
    • Mapped frontends (URL you would enter on a browser) to backends
    nano /etc/traefik/traefik.toml
    debug = false
    
    #Uncomment below if you selfsigned backends
    #insecureSkipVerify = true
    
    logLevel = "ERROR"
    defaultEntryPoints = ["https","http"]
    
    [entryPoints]
    	[entryPoints.http]
    	address = ":80"
    		[entryPoints.http.redirect]
    		entryPoint = "https"
    	[entryPoints.https]
    	address = ":443"
    	[entryPoints.https.tls]
    
    [retry]
    
    [api]
    
    [acme]
    	email = "[email protected]"
    	storage = "/etc/traefik/acme.json"
    	entryPoint = "https"
    	onHostRule = true
    
    [acme.httpChallenge]
    	entryPoint = "http"
    	
    [file]
    
    [backends]
    	[backends.plex]
    		[backends.plex.servers.server1]
    			url = "https://172.16.1.2"
    	[backends.erpnext]
    		[backends.erpnext.servers.server1]
    			url = "http://172.16.1.1"
    
    [frontends]
    		[frontends.plex]
    			backend = "plex"
    			passHostHeader = true
    		[frontends.plex.routes.test_1]
    			rule = "Host:media.domain.com"
    		[frontends.erpnext]
    			backend = "erpnext"
    			passHostHeader = true
    		[frontends.erpnext.routes.test_1]
    			rule = "Host:erp.domain.com"
    

    Next we need to setup the systemd service. The following will setup the restricted systemd file

    nano /etc/systemd/system/traefik.service
    [Unit]
    Description=Traefik
    Documentation=https://docs.traefik.io
    After=network-online.target
    AssertFileIsExecutable=/usr/local/bin/traefik
    AssertPathExists=/etc/traefik
    
    [Service]
    Type=notify
    ExecStart=/usr/local/bin/traefik -c /etc/traefik/traefik.toml
    Restart=always
    WatchdogSec=1s
    ProtectSystem=strict
    ReadWritePaths=/etc/traefik/acme.json
    ReadOnlyPaths=/etc/traefik/traefik.toml
    PrivateTmp=true
    ProtectHome=true
    PrivateDevices=true
    ProtectKernelTunables=true
    ProtectControlGroups=true
    LimitNPROC=1
    
    [Install]
    WantedBy=multi-user.target
    

    Finally, reload the systemd service, enable the traefik service to auto start and start the actual service.

    systemctl daemon-reload
    systemctl enable traefik.service
    systemctl start traefik.service

    Sources:

    https://blog.ssdnodes.com/blog/traefik-multiple-ssl-websites/
    https://blog.cubieserver.de/2018/locking-down-traefik-systemd-service/

  • PowerDNS Recursor – Hiding/Private Zones via LUA

    When deploying PowerDNS Recursor for our customers, we had an issue with how to hide some responses/zones to external IPs. The way we implemented this solution is via LUA scripting.

    -- Set Private Zone
    myDomain = newDN("private.com")
    
    -- Whitelist IPs
    myNetblock = newNMG()
    myNetblock:addMask("192.168.0.0/24")
    myNetblock:addMask("192.168.9.0/24")
    
    function preresolve(dq)
    	if dq.qname:isPartOf(myDomain) and myNetblock:match(dq.remoteaddr) and dq.qtype == pdns.A then
    		-- if the dns requests is for the private zone by trusted IP, proceed to respond.
    		return false
    	elseif dq.qname:isPartOf(myDomain) and dq.qtype == pdns.A then
    		-- if the dns requests is for the private zone by UNtrusted IP, do not respond for A record requests
    		pdnslog ("Remote IP " .. dq.remoteaddr:toString() .. " for domain=" .. dq.qname:toString() .. ", type=" .. tostring(dq.qtype) )
    		return true
    	else
    		-- function normally for everything else.
    		return false
    	end
    end

    In the above example, we set the zone/domain that needs to be private, next select which IP addresses are allowed to see the records and finally the logic via the preresolve() function.