Thursday, January 20, 2022

Docker 101

 Docker 101

Install Docker for Mac

https://docs.docker.com/get-docker/

Create a Container

To create a container in docker, you need to first create a folder.
Within this folder you will need 3 docker files, and the files (code) to run your app.
The docker files are:
  • docker-compose.yaml
  • requirements.txt
  • Dockerfile

The following example here is a flask container, which uses a python script (app.py).
We have 4 files, all located in the same directory. The name of the directory doesn't matter.

app.py
Dockerfile
requirements.txt
docker-compose.yaml

Dockerfile

FROM python:3.8

WORKDIR /app
COPY . .

RUN pip install -r requirements.txt

ENTRYPOINT ["python"]
CMD ["app.py"]

The first thing here is the image which is used as the base image - denoted by the line "FROM python:3.8". Phyton 3.8 is a standard image containing Python. We then add to this image to install additional Python libraries before the program is executed - in this case 'pip install -r requirements.txt'.
Finally the 'Dockerfile' contains what should be executed when the container loads (python app.py). 

requirements.txt

Flask==0.12
flask-restful==0.3.5
flask-mysqldb==0.2.0
mysqlclient==1.4.2.post1

The requirements.txt file simply includes the python libraries which should be installed before the program is executed. This is the same as you would run on your PC - e.g pip install Flask==0.12.

docker-compose.yaml

version: "3.7"

services:
helloworld:
build:
context: ./
ports:
- 5000:5000

The docker-compose.yaml file states how the network requirements for the application - how it should be exposed to the outside world.


We now run the command:
docker compose build
from the directory which includes the 4 files mentioned above.

This will build the container, first downloading the image for python (python:3.8), and then installing the additional python libraries mentioned in the requirements.txt file. The docker image will include all of the files in the directory from where you ran the 'docker compose build' command.

The docker image will be automatically imported to docker running locally on your PC. To view it, run:
docker images

The name of the image = the name of the folder from where you ran the 'docker compose build' command concatenated with and underscore and the name of the service from the docker-compose.yaml file. In this case, my folder name is 'test' and the service name is 'helloworld'. The image name is therefore 'test_helloworld'.

Next, you want to upload the image to docker hub. To do that you first need to setup an account (free) on dockerhub https://hub.docker.com.

In order to upload the image to docker hub you must first login with a browser and create a repository on https://hub.docker.com. Make a note of the name of your repository. You can create a public or private repository. For this example I used a public repository. 

Next, you need to tag your image with your dockerhub username.

If your username is 'my-username', the repository name is 'my-repo', and the image created by 'docker compose build' is named 'testhelloworld', the tag command would be:

docker tag test_helloworld my-username/myrepo:aUniqueTagName

Note 'aUniqueTagName' is used to identify the image you are uploading and will be used in pull requests (downloads) against docker hub. The ':aUniqueTagName' is optional for the docker tag command, but I strongly recommend using it!

If you run docker images again, you will see your tagged image there.

Before uploading the image to docker hub, you must login to docker hub on the command line. To do that, run:


docker login -u your-username -p your-password docker.io


You can now upload your image to docker hub using:


docker push my-username/myrepo:aUniqueTagName



If you are using the image for a kubernetes deployment, in your deployment.yaml file, the image would be referenced as:
spec:
containers:
- name: name-of-your-container
image: docker.io/my-username/myrepo:aUniqueTagName




Other Docker commands

show running containers

docker ps 

show running and stopped containers

docker ps -a













Monday, September 06, 2021

Windows NTFS Apply New Permissions to SubFolders and Files

 icacls D:\MyPath /grant:r "domain\account":(OI)(CI)M /T


Run this from PowerShell:

cmd.exe /c  "icacls D:\MyPath /grant:r 'domain\account':(OI)(CI)M /T" >> $logpath




Monday, July 05, 2021

Azure list Bastion hosts

az network bastion list

Install Azure CLI for Mac

 1) Install Homebrew

https://brew.sh

2) Before doing a 'brew update' you have to run the following commands:

To `brew update`, first run:

  git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow

  git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow


3) Install Azure CLI
https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-macos
brew update && brew install azure-cli

4) Login to Azure
az login


Creating an Ansible Control Server for Windows Targets

Creating an Ansible Control Server for Windows Targets

OS: Ubuntu 16.04 Server on Azure

In order for the Control server to use Windows targets, you need Ansible v2.9 or later.

To get Ansible v2.9, install Ansible using pip3 (apt-get installs an older version of Ansible).

To install Python:

sudo apt install sofware-properties-common

sudo add-apt-repository ppa:deadsnakes/ppa


sudo apt update


sudo apt install python3.8


sudo apt install python3-pip


To install Ansible:

pip3 install ansible


Get ansible version:

ansible --version


Install pywinrm (in order to communicate with Windows targets)

pip3 install "pywinrm>=0.3.0"


Ansible Windows Modules:

win_shell

win_command

win_msi

win_copy


Ansible files required on control host at a minumum

e.g. Inside the folder: /home/azureuser/ansible

2 files: 'hosts' and 'ansible.cfg'

ansible.cfg file - specifies where hosts file is.

hosts (not for prod - passwords are cleartext & no cert validation)

[win]

10.2.0.5


[win:vars]

ansible_user=userWithAdminRightsOnTarget

ansible_password=password

ansible_connection=winrm

ansible_winrm_server_cert_validation=ignore


ansible.cfg

[defaults]

inventory=hosts




Example Playbook

---

- hosts: win

  tasks: 

  - name: Copy File

    win_copy: 

      src: C:\temp\1.txt

      dest: c:\temp2\

      remote_src: yes




Friday, October 30, 2020

Kerberos Test Page (ASP.NET)

 Its old, but this still works and is super useful:

https://docs.microsoft.com/en-us/archive/blogs/friis/asp-net-authentication-test-page

zip file at the bottom of the page to download the files.


Tested successfully on Server 2016. Make sure the app pool is set to 'Classic .NET AppPool' (in Advanced settings for the website).

Also set the normal Authentication settings for a Kerberos site:

- Anonymous Authentication = Disabled

- ASP.NET Impersonation = Enabled

- Windows Authentication = Enabled (and in Providers Negotiate is highest)

<%@ Page Language="C#" %>

<script runat="server">


 protected void dumpObject(object o, Table outputTable)

    {


    try

{

        Type refl_WindowsIdenty = typeof(System.Security.Principal.WindowsIdentity);

        

        System.Reflection.MemberInfo[] refl_WindowsIdenty_members = o.GetType().FindMembers(

                System.Reflection.MemberTypes.Property,

                System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance,

                delegate(System.Reflection.MemberInfo objMemberInfo, Object objSearch) { return true; },

                null);


        foreach (System.Reflection.MemberInfo currentMemberInfo in refl_WindowsIdenty_members)

        {

            TableRow r = new TableRow();

            TableCell k = new TableCell();

            TableCell v = new TableCell();

            System.Reflection.MethodInfo getAccessorInfo = ((System.Reflection.PropertyInfo)currentMemberInfo).GetGetMethod();


            k.Text = currentMemberInfo.Name;

            object value = getAccessorInfo.Invoke(o, null);

            if (typeof(IEnumerable).IsInstanceOfType(value) && !typeof(string).IsInstanceOfType(value))

            {

                foreach (object item in (IEnumerable)value)

                {

                    v.Text += item.ToString() + "<br />";

                }

            }

            else

            {

                v.Text = value.ToString();

            }


            r.Cells.AddRange(new TableCell[] { k, v });

            outputTable.Rows.Add(r);

        }

}

    catch

{}


    }


protected void Page_Load(object sender, EventArgs e)

    {


    AuthMethod.Text = "Anonymous";

    AuthUser.Text = "none";



   //***** Authentication header type (Basic, Negotiate...etc)


   string AUTH_TYPE=Request.ServerVariables["AUTH_TYPE"];

   if (AUTH_TYPE.Length>0) AuthMethod.Text = AUTH_TYPE;


   //***** Authenticated user

   string AUTH_USER=Request.ServerVariables["AUTH_USER"];

   if (AUTH_USER.Length>0) AuthUser.Text  = AUTH_USER;

   

   //***** If NEGOTIATE is used, assume KERBEROS is length of auth. header exceeds 1000 bytes


   if (AuthMethod.Text == "Negotiate")

{

string auth=Request.ServerVariables.Get("HTTP_AUTHORIZATION");

if ((auth!=null)&&(auth.Length > 1000))

AuthMethod.Text = AuthMethod.Text + " (KERBEROS)";

else 

AuthMethod.Text = AuthMethod.Text + " (NTLM)" ;

}



ThreadId.Text=System.Security.Principal.WindowsIdentity.GetCurrent().Name;


        //set the process identity in the corresponding label

        dumpObject(System.Security.Principal.WindowsIdentity.GetCurrent(), tblProcessIdentity);

        

        //set the thread identity in the corresponding lable

        dumpObject(System.Threading.Thread.CurrentPrincipal.Identity, tblThreadIdentity);


int loop1, loop2;

NameValueCollection coll;


// Load ServerVariable collection into NameValueCollection object.

coll=Request.ServerVariables; 

// Get names of all keys into a string array. 

String[] arr1 = coll.AllKeys; 

for (loop1 = 0; loop1 < arr1.Length; loop1++) 

{

TableRow r = new TableRow();

        TableCell k = new TableCell();

                TableCell v = new TableCell();

k.Text=arr1[loop1];

     String[] arr2=coll.GetValues(arr1[loop1]);


for (loop2 = 0; loop2 < arr2.Length; loop2++) {

      v.Text=v.Text+Server.HtmlEncode(arr2[loop2]);

  }



  v.Text=Server.HtmlEncode(arr2[0]);

r.Cells.AddRange(new TableCell[] { k, v });

tblSrvVar.Rows.Add(r);

}


/*

IEnumerator en = Request.ServerVariables.Keys.GetEnumerator();

en.MoveNext(); 


foreach (string key in Request.ServerVariables.Keys) 

{ 

TableRow r = new TableRow();

        TableCell k = new TableCell();

                TableCell v = new TableCell();

k.Text = key;

v.Text=Request.ServerVariables[key];

r.Cells.AddRange(new TableCell[] { k, v });

tblSrvVar.Rows.Add(r);

}*/


    }

    

</script>


<html>

<body>

<font face="Verdana">

<center><H2>WHO Page</H2><br>

<table border=1>

<tr>

<td><img src="img1.gif"></td>

<td><img src="img2.gif"></td>

<td><img src="img3.gif"></td>

<td><img src="img4.gif"></td>

<td><img src="img5.gif"></td>

<td><img src="img6.gif"></td>

<td><img src="img7.gif"></td>

<td><img src="img8.gif"></td>

<td><img src="img9.gif"></td>

<td><img src="img10.gif"></td>

</tr>

</table>

</center>

<table border=1>

<tr><td>Authentication Method </td><td><b><asp:label id=AuthMethod runat=server/></b></td><td>Request.ServerVariables("AUTH_TYPE")</td></tr>

<tr><td>Identity </td><td><b><asp:label id=AuthUser runat=server /></b></td><td>Request.ServerVariables("AUTH_USER") or System.Threading.Thread.CurrentPrincipal.Identity</td></tr>

<tr><td>Windows identity </td><td> <b><asp:label id=ThreadId runat=server /></b></td><td>System.Security.Principal.WindowsIdentity.Getcurrent</td></tr>

</table>


<fieldset>

            <label>Identity (System.Threading.Thread.CurrentPrincipal.Identity)</label>

            <asp:Table ID="tblThreadIdentity" runat="server"></asp:Table>

        </fieldset>



<fieldset>

            <label>Windows Identity (System.Security.Principal.WindowsIdentity.GetCurrent)</label>

            <asp:Table ID="tblProcessIdentity" runat="server"></asp:Table>

        </fieldset>


Dump of server variables :

<br><br>

<asp:Table ID="tblSrvVar" runat="server"></asp:Table>


<form name="form1" method="POST" action="default.aspx">

Sample Form<br>

<input NAME="sometext" TYPE="Text" SIZE="24">

<input TYPE="submit" VALUE="Submit" NAME="SubmitForm" > 

</form>


</font>

</body>

</html> 


Thursday, November 08, 2018

C# XmlDocument Example




static void LoadCopySources()
        {
           
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(xmlfilename);

            var serverList = xmlDoc.SelectNodes("//servers/server");
            foreach (XmlNode aServer in serverList)
            {
                Console.WriteLine(aServer.Attributes["name"].Value);

                var memList = aServer.SelectNodes("servicestomonitor/service");

                foreach (XmlNode x in memList)
                {
                    Console.WriteLine(x.InnerText);
                }
            }

            var copySourceList = xmlDoc.SelectNodes("//copysources/copysource");
            foreach (XmlNode src in copySourceList)
            {
                //Console.WriteLine(src.InnerXml);
                LstCopySources.Add(src.InnerXml);
            }


            foreach(var astr in LstCopySources)
            {
                Console.WriteLine(astr);
            }
            Console.WriteLine("stop");
        }

Thursday, February 18, 2016

Citrix Web Interface User Roaming And Citrix StoreFront Multi-Site

Web Interface (version 5.2+) has a handy feature which limits enumeration of farms depending on group membership. In Web Interface this feature is called "User Roaming" - note this is NOT "Session Roaming".
Lets say your WI is configured to enumerate resources from 2 XA farms. One farm is in the UK, the other is in the US. For the UK WI, you want the UK users to logon to resources in the UK XA farm and US users to logon to resources in the US XA farm.
To do this you would modify the webinterface.conf file.
If the farms are defined as:
Farm1=UKXA1.domain.com,Name=UkFarm,...
Farm2=USXA1.domain.com,Name=UsFarm,...
Then, the AD groups you allow to enumerate that farm are defined as:
Farm1Groups=domain\UKUsers
Farm2Groups=domain\USUsers

How is this configured in StoreFront?
The equivalent feature in StoreFront is called 'User Farm Mapping' which is part of the StoreFront 'Multi-Site' functionality. In StoreFront, the web.config file of the site needs to be modified.
The web.config file can be found in C:\inetpub\wwwroot\Citrix\store_name
Note that store_name is the name of the Store, not the name of the 'Receiver for Web' site.



Within the web.config file, find the XML element 'resourcesWingConfigurations'.
By default it should look like:

Within the "resourcesWingConfigurations" element, create a new "resourcesWingConfiguration" element (the child element is not a plural)..



The new "resourcesWingConfiguration" above allows only members of the 'domain\UKUsers' AD group to be enumerated resources from the 'Controller' site.

Note:
  • The farm name here is "Controller". This is the default farm name which the StoreFront Administration Console assigns to the first Site you configure.
  • You must also specify the SID of the Active Directory group. This can be easily found using a utility such as PsGetSid from SysInternals.
  • Optionally you can specify a Backup farm in case the StoreFront server is unable to contact the primary farm Controller(s).


How to check the name of the farm
Two methods:
1) Open the Citrix StoreFront console, select the store and click 'Manage Delivery Controllers'


2) Check in the web.config file for the store. The farm name will be inside the element.


Citrix StoreFront 3.0.1.57 was used to validate this procedure.

Wednesday, February 17, 2016

Smart Access in Citrix XenApp/XenDeskop 7

Smart Access is a useful Citrix feature which allows you to set specific Citrix policies depending on where the user is accessing from. For example a common use of Smart Access is to disable drive mapping for users connecting from the Internet (via a NetScaler gateway).

Two important things to note:
1) The XML broker which the StoreFront server is using must be set to trust XML requests.
2) In the policy filter, the "NetScaler Gateway farm name" = the name of the NetScaler Gateway vServer which is configured in the NetScaler Configuration manager.

In the screenshot above, the NetScaler Gateway farm name is "XD2". This is the name of the NetScaler Gateway vServer as can be seen below:


To Trust XML Requests on the Controller:
Set-BrokerSite -TrustRequestsSentToTheXmlServicePort $true


With these configured the Smart Access policies should apply successfully.

Tuesday, August 02, 2011

Remove Metadata of a failed DC

http://support.microsoft.com/kb/216498

Had to follow this for a failed DC (one of four), though it fortunately was not a FSMO role holder. Took a while to complete, but all went through successfully. DC was then rebuilt from scratch, and DCPromo'd again.

Find FSMO roles quickly

netdom query fsmo

DC Ntbackup script

http://briandesmond.com/blog/managing-local-backups-with-windows-server-backup/

Useful for using a 2-tiered approach to DC system state backups - i.e. this script drops the backup locally on the DC it is running on, then you can use a third party backup tool (e.g. Netbackup etc) to pick up the files from there.
You can keep a couple of weeks worth of backups locally on the DC. If you need to restore you quickly have access to the backup files without having to bother your backup team and don't have to wait for a long over-WAN restore.

Monday, March 22, 2010

Favourite ESX Commands

man

ls -al

lsof - list open files

esxtop
c = cpu stats
m = memory
n = network
d = disk
u = disk device (new in 3.5)
v = disk VM (new in 3.5)
s = change update interval (min = 2seconds)
f = choose fields (interactive selection)

esxcfg

lspci - list all pci devices

date

View Volume sizes, Used and Available space
vdf -h (h is 'human readable')
This is an ESX version of the linux DF command. The same command options and syntax applies.

command "| more" one page at a time

command "| grep string" = search output for string

vmkping = ping from the kernel nic
(ping command uses service console interface)

change password
pwd

---------------------------
configure ssh to allow the root user to login Update the ssh configuration file:
vi /etc/ssh/sshd_config

PermitRootLogin yes

Restart the sshdaemon:
service sshd restart

[login over SSH (e.g. Putty or SecureCRT) with a non root account and then SU to super user into root mode].
----------------------------

clear = clear the screen

vmware -v = version

df = disk usage

vdf -h = vhdk disk usage

passwd user = change password for user

useradd test10 = add a new user with username test10

last reboot

last = last users

esxcfg-nics -l
show physical nics and speed

esxcfg-vswif -l
show console ports

esxcfg-vswitch -l
show virtual switches

display cpu and memory usage
top
to quit type q enter

kudzu - detects and configures new hardware
-s runs in safe mode - doesnt disturb hardware.
updates the file /etc/sysconfig/hwconf (currently installed hardware)

cat - equivalent to type command in dos - prints a file to the standard output

Linux Permissions (view using ls -l)
TypeReadWriteExecuteReadWriteExecuteReadWriteExecute
drwx
rwx
rwx

Type can be:
d = directory
l = symbolic link
s = socket
p = named pipe
- = regular file
c= character (unbuffered) device file special
b=block (buffered) device file special

1st rwx = permissions for the owner of the file
2nd rwx = permissions for the group owning the file
3rd rwx = permissions for all other users

nano - text editor similar to VI
Ctrl + X to quit.

Nameserver info held in file:
/etc/resolv.conf

Hosts file
/etc/hosts

See iScsi connections:
cat /proc/scsi/iscsi_vmk/5

Clone a vmdk
vmkfstools -i original.vmdk new.vmdk

-d - optionally specify a disk format (e.g vmfs, thin).