Examples of States

Usefull commands

On VultureOS

Without salt master:

salt-call state.apply --local

Apply a specific state:

salt-call state.apply vulture.frontend_present

Increase verbosity:

salt-call state.apply -ldebug

Test a state with a dry run:

salt-call state.apply test=True

On salt master

salt "<appliance hostname>" cmd.run "salt-call state.apply"
salt --hide-timeout -t5 -C "G@roles:<group name>" cmd.run "cat /etc/resolv.conf"

Configuration example

Be sure to specify required dependencies in the state.

For example, a workflow needs at least a frontend and a backend so in the workflow state, you have to delcare them in requirements

state_workflow_present:
  vulture.workflow_present:
    - require:
      - id: state_frontend_present
      - id: state_backend_present

Whitelist

state_whitelist_salt_master:
  vulture.whitelist_salt_master:
    - name: "Salt Master IP"
    - ip_address: 10.0.2.1

Node

state_node_present:
  vulture.node_present:
    - require:
      - id: state_forwarder_present
    - data:
      - name: "vulture"
        static_routes: |-
          static_routes="net1 net2 net3"
          route_net1="-net 192.168.0.0/24 192.168.0.1"
          route_net2="-net 192.168.1.0/24 192.168.1.1"
          route_net3="-net 192.168.2.0/24 192.168.2.1"
        pf_custom_param_config: "### Custom global parameters test"
        pf_custom_rdr_config: |-
          ### Custom RDR rules
          nat inet from 127.0.0.5 to any -> (vmx0)
        pstats_forwarders:
          - syslog_forwarder

Network Interface

state_netif_present:
  vulture.netif_present:
    - data:
      - net_int_device:
        - dev: vtnet0
          node_name: vulture

Network Address

state_network_address_present:
  vulture.network_address_present:
    - require:
      - id: state_netif_present
    - data:
      - name: System
        type: system
        ip: 10.0.2.2
        prefix_or_netmask: "255.255.255.0"
        net_int_device:
          - dev: vtnet0
            node_name: vulture

TLS Profile

state_tlsprofile_present:
  vulture.tlsprofile_present:
    - data:
      - id: 2
        name: Custom TLS profile
        x509_certificate: vulture
        protocols:
          - tlsv11
          - tlsv12
          - tlsv13
        cipher_suite: "broad"
        alpn:
          - h2
          - http/1.1
        verify_client: "none"
        ca_cert: null

Log Forwarder

state_forwarder_present:
  vulture.forwarder_present:
    - data:
      - forwarder_type: File
        name: file_forwarder
        file: /tmp/testing
        flush_interval: 2
      - forwarder_type: File
        name: file_forwarder_raw
        file: /tmp/raw
        flush_interval: 2
        send_as_raw: True
      - forwarder_type: RELP
        name: relp_forwarder
        target: 10.0.2.1
        port: 2323
        tls_enabled: True
      - forwarder_type: Redis
        name: redis_forwarder
        target: 127.0.0.5
        port: 6379
        key: "%$!techno%-%$!product%"
        dynamic_key: true
      - forwarder_type: Syslog
        name: syslog_forwarder
        target: 10.0.2.1
        port: 2424
        protocol: tcp
        zip_level: 4
      - forwarder_type: Elasticsearch
        name: ELS_forwarder
        servers: '["http://10.0.2.1:9200"]'
        es8_compatibility: True
        data_stream_mode: True
        index_pattern: "vulture-%$!timestamp:1:10%"
        enable_retry: True
        enable_disk_assist: True
      - forwarder_type: MongoDB
        name: mongodb_forwarder
        uristr: "mongodb://10.0.2.10:9091/?replicaset=Vulture&ssl=true"
        db: vulture
        collection: logs_mongodb_forwarder
      - forwarder_type: Kafka
        name: kafka_forwarder
        broker: '["10.0.2.1:9092"]'
        topic: logs
        dynaTopic: False
        key: "%$!techno%-%$!product%"
        dynaKey: True
        topicConfParam:
          - test="is a string"
          - test2=ok
        confParam:
          - a=b
          - c=d
          - e=f=gchoices.OPENIDChoices.JWT_SIGNATURE_TYPE[0]
        partitions_auto: True

Error Templates

state_error_template_present:
  vulture.error_template_present:
    - data:
      - name: Test_Error_Template
        error_400_mode: display
        error_400_html: "HTTP/1.1 400 Bad Request\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>400 Bad requesting</h1>\r\n<p>Your browser sent an invalid request.</p>\r\n</body></html>"
        error_400_url: "http://www.example.com/test/"
        error_403_mode: display
        error_403_html: "HTTP/1.1 403 Forbidden\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>403 Forbidden</h1>\r\n<p>You don't have permission to access this url on this server.<br/></p>\r\n</body></html>"
        error_403_url: "http://www.example.com/test/"
        error_405_mode: display
        error_405_html: "HTTP/1.1 405 Method Not Allowed\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>405 Method Not Allowed</h1>\r\n<p>The requested method is not allowed for that URL.</p>\r\n</body></html>"
        error_405_url: "http://www.example.com/test/"
        error_408_mode: display
        error_408_html: "HTTP/1.1 408 Request Timeout\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>408 Request Timeout</h1>\r\n<p>Server timeout waiting for the HTTP request from the client.</p>\r\n</body></html>"
        error_408_url: "http://www.example.com/test/"
        error_425_mode: display
        error_425_html: "HTTP/1.1 425 Too Early\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>425 Too Early</h1>\r\n<p>.</p>\r\n</body></html>"
        error_425_url: "http://www.example.com/test/"
        error_429_mode: display
        error_429_html: "HTTP/1.1 429 Too Many Requests\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>429 Too Many Requests</h1>\r\n<p>The user has sent too many requests in a given amount of time.</p>\r\n</body></html>"
        error_429_url: "http://www.example.com/test/"
        error_500_mode: display
        error_500_html: "HTTP/1.1 500 Internal Server ErrTest_Error_Templateor\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>500 Internal Server Error</h1>\r\n<p>The server encountered an internal error or\r\nmisconfiguration and was unable to complete\r\nyour request.</p>\r\n<p>Please contact the server administrator\r\nto inform them of the time this error occurred\r\nand the actions you performed just before this error.</p>\r\n<p>More information about this error may be available\r\nin the server error log.</p>\r\n</body></html>"
        error_500_url: "http://www.example.com/test/"
        error_502_mode: display
        error_502_html: "HTTP/1.1 502 Bad Gateway\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>502 Bad Gateway</h1>\r\n<p>The proxy server received an invalid response from an upstream server.<br/></p>\r\n</body></html>"
        error_502_url: "http://www.example.com/test/"
        error_503_mode: display
        error_503_html: "HTTP/1.1 503 Service Unavailable\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>503 Service Unavailable</h1>\r\n<p>The server is temporarily unable to service your\r\nrequest due to maintenance downtime or capacity\r\nproblems. Please try again later.</p>\r\n</body></html>"
        error_503_url: "http://www.example.com/test/"
        error_504_mode: display
        error_504_html: "HTTP/1.1 504 Gateway Timeout\r\nContent-type: text/html\r\nConnection: close\r\n\r\n\r\n<html><body><h1>504 Gateway Timeout</h1>\r\n<p>The gateway did not receive a timely response\r\nfrom the upstream server or application.</p>\r\n</body></html>"
        error_504_url: "http://www.example.com/test/"

Frontend and listener

state_frontend_present:
  vulture.frontend_present:
    - require:
      - id: state_network_address_present
      - id: state_tlsprofile_present
      - id: state_error_template_present
    - data:
      - name: HTTPS
        mode: http
        https_redirect: true
        listeners:
          - interface_name: System
            ip: 10.0.2.10
            port: 443
            tls_profiles:
              - Custom TLS profile
          - interface_name: System
            ip: 10.0.2.10
            port: 80
        enable_logging_reputation: false
        enable_logging: true
        error_template: Test_Error_Template
        log_forwarders:
          - redis_forwarder
        log_condition: |
          {%raw%}{{redis_forwarder}}{%endraw%}
      - name: Frontend ssh
        mode: tcp
        listeners:
          - interface_name: System
            ip: 10.0.2.10
            port: 2222
        enable_logging_reputation: false
        enable_logging: false
      - name: Filebeat example
        mode: filebeat
        filebeat_listening_mode: api
        node: vulture
        listeners:
          - interface_name: System
            ip: 10.0.2.10
            port: 4444
        enable_logging_reputation: false
        enable_logging: true
        log_forwarders:
          - file_forwarder
        log_condition: |
          {%raw%}{{file_forwarder}}{%endraw%}
        filebeat_module: "f5"
        filebeat_config: |
          - module: f5
            bigipapm:
              enabled: true
              var.input: tcp
              var.syslog_host: %ip%
              var.syslog_port: %port%
        api_parser_use_proxy: true
        api_parser_custom_proxy: "http://10.0.2.1:3128"
        ruleset: "generic_json"
      - name: Redis Input json
        mode: log
        listening_mode: redis
        node: vulture
        ruleset: "generic_json"
        redis_server: 127.0.0.5
        redis_port: 6379
        redis_mode: queue
        redis_key: redis_input
        nb_workers: 2
        redis_batch_size: 100
        mmdb_cache_size: 10000
        enable_logging: true
        enable_logging_geoip: True
        logging_geoip_database: "Geolite2 Country"
        log_forwarders:
          - file_forwarder
          - redis_forwarder
        log_condition: |
          {%raw%}{{file_forwarder}}
          {{redis_forwarder}}{%endraw%}
      - name: Syslog input
        mode: log
        listening_mode: tcp
        ruleset: "raw_to_json"
        custom_tl_frame_delimiter: 200
        listeners:
          - interface_name: System
            ip: 10.0.2.10
            port: 7841
        enable_logging: true
        enable_logging_geoip: True
        logging_geoip_database: "Geolite2 City"
        log_forwarders:
          - file_forwarder_raw
          - mongodb_forwarder
          - kafka_forwarder
          - ELS_forwarder
        log_forwarders_parse_failure:
          - file_forwarder_raw
        log_condition: |
          {%raw%}{{file_forwarder_raw}}
          {{mongodb_forwarder}}
          {{kafka_forwarder}}
          {{ELS_forwarder}}{%endraw%}

Backend

state_backend_present:
  vulture.backend_present:
    - data:
      - name: app1
        mode: http
        timeout_server: 1000
        timeout_connect: 1000
        balancing_mode: roundrobin
        servers:
          - port: 8004
            target: app1.web.lan
            weight: 1
            mode: net
        enable_http_health_check: True
        http_health_check_expect_match: rstatus
        http_health_check_expect_pattern: 302
      - name: app2
        mode: http
        timeout_server: 1000
        timeout_connect: 1000
        balancing_mode: roundrobin
        servers:
          - port: 8006
            target: app2.web.lan
            weight: 1
            mode: net
      - name: app3
        mode: http
        timeout_server: 1000
        timeout_connect: 1000
        balancing_mode: roundrobin
        servers:
          - port: 8008
            target: app31.web.lan
            weight: 1
            mode: net
          - port: 8008
            target: app32.web.lan
            weight: 1
            mode: net
      - name: custom
        mode: http
        timeout_server: 1000
        timeout_connect: 1000
        balancing_mode: roundrobin
        servers:
          - port: 80
            target: 10.0.2.1
            weight: 1
            mode: net
        enable_http_health_check: True
        http_health_check_expect_match: rstatus
        http_health_check_expect_pattern: 200
      - name: ssh
        mode: tcp
        timeout_server: 1000
        timeout_connect: 1000
        balancing_mode: roundrobin
        servers:
          - port: 22
            target: 10.0.2.1
            weight: 1
            mode: net
        enable_tcp_health_check: True
        tcp_health_check_expect_match: rstring
        tcp_health_check_expect_pattern: ^SSH.\*OpenSSH.\*
        tcp_health_check_interval: 10

LDAP repository

state_ldaprepository_present:
  vulture.ldaprepository_present:
    - data:
      - name: LDAP_Main
        host: 10.0.2.1
        port: 6389
        protocol: 3
        encryption_scheme: none
        connection_dn: cn=admin,dc=web,dc=lan
        dn_password: admin
        base_dn: dc=web,dc=lan
        user_scope: 2
        user_dn: ou=users
        user_attr: uid
        user_objectclasses:
          - top
          - inetOrgPerson
          - customAuxiliaryClass
        group_objectclasses:
          - top
          - groupOfNames
          - extensibleObject
        user_groups_attr: memberOf
        user_filter: (objectClass=inetOrgPerson)
        user_account_locked_attr: ""
        user_change_password_attr: ""
        user_mobile_attr: mobile
        user_email_attr: mail
        group_scope: 2
        group_dn: ou=Policy
        group_attr: cn
        group_filter: (objectClass=groupOfNames)
        group_member_attr: member
        custom_attributes:
          - ldap_attribute: CustomAttr1
            output_attribute: my_attr_1
          - ldap_attribute: CustomAttr2
            output_attribute: my_attr_2

User Scope

state_userscope_present:
  vulture.userscope_present:
    - data:
      - name: Gitlab Scopes
        repo_attributes:
          - condition_var_kind: always
            assignator: "="
            action_var_name: user_type
            action_var_kind: constant
            action_var: "user"
          - condition_var_kind: claim
            condition_var_name: groups
            condition_criterion: exists
            condition_match: ""
            assignator: +=
            action_var_name: claim_list
            action_var_kind: claim
            action_var: claim_list
          - condition_var_kind: claim
            condition_var_name: email
            condition_criterion: exists
            condition_match: ""
            assignator: "="
            action_var_name: mail
            action_var_kind: claim
            action_var: email
          - condition_var_kind: claim
            condition_var_name: mobile
            condition_criterion: exists
            assignator: "="
            action_var_name: mobile
            action_var_kind: claim
            action_var: mobile
          - condition_var_kind: claim
            condition_var_name: iss
            condition_criterion: exists
            assignator: "="
            action_var_name: iss
            action_var_kind: claim
            action_var: iss

IDP

state_gitlab_connector_present:
  vulture.openid_present:
    - require:
      - state_userscope_present
    - data:
      - name: Gitlab
        provider: gitlab
        provider_url: https://gitlab.com
        client_id: <client_id>
        client_secret: <client_secret>
        scopes:
          - openid
          - read_user
          - profile
          - email
        use_proxy: false
        verify_certificate: true
        user_scope: Gitlab Scopes
        enable_jwt: True
        jwt_signature_type: RS256
        jwt_key: |
          -----BEGIN CERTIFICATE-----
          <certificate>
          -----END CERTIFICATE-----

OTP

state_otp_present:
  vulture.otp_present:
    - data:
      - name: "Default TOTP"
        otp_type: "totp"
        totp_label: "Double Authentication"

User Portal

state_userportal_present:
  vulture.userportal_present:
    - require:
      - id: state_frontend_present
      - id: state_userscope_present
      - id: state_gitlab_connector_present
    - data:
      - name: PortalAppsGitlab
        repositories:
          - Gitlab
        auth_type: form
        auth_timeout: 3600
        enable_timeout_restart: true
        disconnect_url: "/disconnect"
        enable_disconnect_message: true
        enable_disconnect_portal: true
        enable_oauth: false
        enable_sso_forward: false
      - name: PortalAppsMixed
        repositories:
          - Gitlab
          - LDAP_Main
        auth_type: form
        auth_timeout: 3600
        enable_timeout_restart: true
        disconnect_url: "/disconnect"
        enable_disconnect_message: true
        enable_disconnect_portal: true
        enable_oauth: false
        enable_sso_forward: false
      - name: PortalCustom
        enable_external: false
        repositories:
          - LDAP_Main
        auth_type: form
        oauth_timeout: 3600
        enable_timeout_restart: false
        disconnect_url: "/disconnect"
        enable_disconnect_message: true
        enable_disconnect_portal: true
        enable_registration: false
        enable_sso_forward: false

ACL

state_acl_present:
  vulture.acl_present:
    - data:
      - name: "Internal_IP_source"
        enabled: true
        or_lines:
          - lines:
            - criterion: "src"
              converter: "ip"
              dns: false
              case: false
              pattern: "10.0.2.0/24"

Workflow

state_workflow_present:
  vulture.workflow_present:
    - require:
      - id: state_frontend_present
      - id: state_backend_present
      - id: state_userportal_present
      - id: state_acl_present
    - data:
      - name: app1
        frontend: HTTPS
        authentication: PortalAppsGitlab
        backend: app1
        fqdn: app1.web.lan
        public_dir: /
      - name: app2
        frontend: HTTPS
        authentication: PortalAppsGitlab
        backend: app2
        fqdn: app2.web.lan
        public_dir: /myapp/
        enable_cors_policy: true
        cors_allowed_methods:
          - "GET"
          - "POST"
          - "OPTIONS"
        cors_allowed_origins: "*"
        cors_allowed_headers: "*"
        cors_max_age: 3600
      - name: lb_app
        frontend: HTTPS
        authentication: PortalAppsGitlab
        backend: app3
        fqdn: app3.web.lan
        public_dir: /
        acl_frontend:
          - name: Internal_IP_source
            action_satisfy: 200
            action_not_satisfy: 403
      - name: admin_app
        frontend: HTTPS
        authentication: PortalAppsMixed
        backend: custom
        fqdn: admin.web.lan
        public_dir: /
        acl_frontend:
          - name: Internal_IP_source
            action_satisfy: 200
            action_not_satisfy: 403
      - name: Internal ssh
        frontend: Frontend ssh
        backend: ssh