saltssh of Saltstack and Application of its API

Article Directory

ssh

Introduction to saltssh

Basic Definitions

  • Sal-ssh manages the server by executing commands through the SSH protocol. There is no need to install minion client on the server side. Minion module can also be called if minion is installed. Sal-ssh is a bit like ansible client-free base and SSH protocol to manage the server by roser(/etc/salt/roser) configuration file.

Application Scenarios

  • The main function is that minion does not need to be installed. As long as the SSH protocol is open, commands can be executed remotely, used to get a batch of new machines, used in batch configuration, or managed directly by salt-ssh without minion being installed.
  • The salt ssh system does not completely replace the salt communication system.It is simply based on ssh protocol and does not rely on ZeroMQ and salt-minion, but since salt ssh is based on ssh protocol completely, it is far less efficient to execute ssh remotely than ZeroMQ.
  • The roster system was created because salt-ssh relies on this list to determine which systems are connected and executed.
  • Because this roster system is of the "hot-plug" type, it enhances attachment to any existing system to collect information about which servers are currently available and which can be connected using salt-ssh

Note: Minion is not installed in this experimental environment and master and minion need not be turned on.

server2(minion)

  • Turn off the minion service to allow us to observe the experimental phenomena.
[root@server2 ~]# systemctl stop salt-minion   #Stop viewing experimental phenomena

server1(master)

  • Install salt-ssh.
[root@server1 2019]# yum install salt-ssh -y
  • Edit the configuration file to add hosts to ssh connection:
[root@server1 2019]# cd /etc/salt/
[root@server1 salt]# vim roster
server2:
  host: 172.25.11.2
  user: root    #User and password to ssh connection
  passwd: redhat

test

  • Test directly after the configuration is successful and you can see that the result of ping is true.
[root@server1 salt]# salt-ssh '*' test.ping

  • View partitions for server2
[root@server1 salt]# salt-ssh server2 -r 'df'   #View partitions for server2

  • View the hostname of server2.
[root@server1 salt]# salt-ssh server2 -r 'hostname'

API

server2(minion)

  • Open the service you just closed again on server2.
[root@server2 ~]# systemctl start salt-minion   #Open the closed service again

server1(master)

  • Install salt-api on server1.
[root@server1 salt]# yum install salt-api -y

  • Generate a key in the / etc/pki/tls/private/directory.
[root@server1 salt]# cd /etc/pki/tls/
[root@server1 tls]# cd private/
[root@server1 private]# openssl genrsa 2048 > localhost.key    #Generate key
[root@server1 private]# cat localhost.key   #View generated


  • Generate a certificate in the / etc/pki/tls/certs directory because there is a makefile file under this directory that contains the appropriate way to generate a certificate, using the key to generate the certificate
[root@server1 private]# cd ..
[root@server1 tls]# cd certs/
[root@server1 certs]# make testcert    #Generate Certificate

  • On server1/etc/salt, check that the master file contains the directory of the corresponding api module file and its file naming format. The api template file must be in the master.d directory and end with.conf.
[root@server1 ~]# vim /etc/salt/master    #Naming format and file path written in
12 #default_include: master.d/*.conf

  • Edit the api's profile in the / etc/salt/master.d directory to add the certificate and its key in the format of the official website.
  • Official website: https://docs.saltstack.com/en/latest/topics/eauth/index.html#acl-eauth
[root@server1 certs]# vim /etc/salt/master.d/api.conf    #So create a new file as required
rest_cherrypy:
  port: 8000    #Open Port
  ssl_crt: /etc/pki/tls/certs/localhost.crt
  ssl_key: /etc/pki/tls/private/localhost.key
  • Make sure the path to the certificate and private key in the api file is correct.
[root@server1 certs]# ll /etc/pki/tls/certs/localhost.crt   #The above certificate and key can be found in the system
[root@server1 certs]# ll /etc/pki/tls/private/localhost.key

  • Similarly, create a new certification file in the / etc/salt/master.d directory and write it in the format of your official website.
[root@server1 master.d]# vim /etc/salt/master.d/auth.conf   #authenticated document

external_auth:
  pam:
    saltdev:    #User name
      - '.*'
      - '@wheel'   #Allow all wheel modules
      - '@runner'
      - '@jobs'

  • Add the user saltdev and change the password to saltdev.
[root@server1 master.d]# useradd saltdev   #Add the saltdev user written in the file above and change his password to saltdev to match the official website
[root@server1 master.d]# passwd saltdev
  • Open the salt-api service, restart the salt-master service, and check if port 8000 was successfully opened.
[root@server1 ~]# systemctl restart salt-master
[root@server1 ~]# systemctl start salt-api
[root@server1 ~]# netstat -antlp   #View port 8000 open

  • Log in and get token.
[root@server1 ~]# curl -sSk https://localhost:8000/login \#Log on, get token
>     -H 'Accept: application/x-yaml' \
>     -d username=saltdev \
>     -d password=saltdev \
>     -d eauth=pam

  • Using the token you just made, execute the test.ping command to detect all minion ends.
#Using the token you just made, execute the test.ping command to detect all minion ends.
[root@server1 ~]# curl -sSk https://localhost:8000     -H 'Accept: application/x-yaml'     -H 'X-Auth-Token:b4d2689c7630149c88c29408d174022dd92765bb' \      
>     -d client=local \
>     -d tgt='*' \     #Goal is *
>     -d fun=test.ping

Python OMT

  • The github website can find files written by others to learn from.

Print all minion s that get key s under the master node

[root@server1 ~]# vim saltapi.py   #Write a python script

import urllib2,urllib
import time

try:
    import json
except ImportError:
    import simplejson as json

class SaltAPI(object):
    __token_id = ''
    def __init__(self,url,username,password):
        self.__url = url.rstrip('/')
        self.__user = username
        self.__password = password

    def token_id(self):
        ''' user login and get token id '''
        params = {'eauth': 'pam', 'username': self.__user, 'password': self.__password}
        encode = urllib.urlencode(params)
        obj = urllib.unquote(encode)
        content = self.postRequest(obj,prefix='/login')
        try:
            self.__token_id = content['return'][0]['token']
        except KeyError:
            raise KeyError

    def postRequest(self,obj,prefix='/'):
        url = self.__url + prefix
        headers = {'X-Auth-Token'   : self.__token_id}
        req = urllib2.Request(url, obj, headers)
        opener = urllib2.urlopen(req)
        content = json.loads(opener.read())
        return content

    def list_all_key(self):
        params = {'client': 'wheel', 'fun': 'key.list_all'}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        minions = content['return'][0]['data']['return']['minions']
        minions_pre = content['return'][0]['data']['return']['minions_pre']
        return minions,minions_pre

    def delete_key(self,node_name):
        params = {'client': 'wheel', 'fun': 'key.delete', 'match': node_name}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]['data']['success']
        return ret

    def accept_key(self,node_name):
        params = {'client': 'wheel', 'fun': 'key.accept', 'match': node_name}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0]['data']['success']
        return ret

    def remote_noarg_execution(self,tgt,fun):
        ''' Execute commands without parameters '''
        params = {'client': 'local', 'tgt': tgt, 'fun': fun}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0][tgt]
        return ret

    def remote_execution(self,tgt,fun,arg):
        ''' Command execution with parameters '''
        params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        ret = content['return'][0][tgt]
        return ret

    def target_remote_execution(self,tgt,fun,arg):
        ''' Use targeting for remote execution '''
        params = {'client': 'local', 'tgt': tgt, 'fun': fun, 'arg': arg, 'expr_form': 'nodegroup'}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        jid = content['return'][0]['jid']
        return jid

    def deploy(self,tgt,arg):
        ''' Module deployment '''
        params = {'client': 'local', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        return content

    def async_deploy(self,tgt,arg):
        ''' Asynchronously send a command to connected minions '''
        params = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        jid = content['return'][0]['jid']
        return jid

    def target_deploy(self,tgt,arg):
        ''' Based on the node group forms deployment '''
        params = {'client': 'local_async', 'tgt': tgt, 'fun': 'state.sls', 'arg': arg, 'expr_form': 'nodegroup'}
        obj = urllib.urlencode(params)
        self.token_id()
        content = self.postRequest(obj)
        jid = content['return'][0]['jid']
        return jid

def main():
    sapi = SaltAPI(url='https://localhost:8000',username='saltdev',password='saltdev') #Modify the three parameters of this line Note that https
    #sapi.token_id()
    print sapi.list_all_key()      #Cancel Note Printing
    #sapi.delete_key('test-01')
    #sapi.accept_key('test-01')
    #sapi.deploy('test-01','nginx')
    #print sapi.remote_noarg_execution('test-01','grains.items')

if __name__ == '__main__':
    main()
  • Two modifications were made.
  • Execute this script to see the results.
[root@server1 ~]# python saltapi.py
 Print out server2 and server3

  • List all allowed key s.
[root@server1 ~]# salt-key -L

Open the httpd service for server2

  • Modify the.py file again to open the apache service for server2.
  • Note: You must ensure that the corresponding SLS installation and its startup service install.sls or service.sls files are available in the base directory (/srv/salt)
  • Review the process before modifying: ps ax, you can see that the httpd service is not open at this time.
  • Modify the file and execute it.
[root@server1 ~]# vim saltapi.py 
[root@server1 ~]# python saltapi.py 

  • server2 looks at the process again and opens httpd to serve ps ax

Open the nginx service for server3

  • Note: You must ensure that the corresponding SLS installation and its startup service install.sls or service.sls files are available in the base directory (/srv/salt)
  • Open nginx for server3, edit the py file, and execute.
[root@server1 ~]# vim saltapi.py 
[root@server1 ~]# python saltapi.py

  • Viewing the process ps ax in server3, nginx was successfully opened.

    Note: It is possible for server3 to turn on httpd, close apache, execute the python script once more, and then view the nginx process.

Keywords: ssh Python vim Nginx

Added by xgab on Wed, 21 Aug 2019 04:22:01 +0300