github.com/crowdsecurity/crowdsec@v1.6.1/docker/test/tests/test_tls.py (about)

     1  #!/usr/bin/env python
     2  
     3  """
     4  Test agent-lapi and cscli-lapi communication via TLS, on the same container.
     5  """
     6  
     7  import uuid
     8  
     9  from pytest_cs import Status
    10  
    11  import pytest
    12  
    13  pytestmark = pytest.mark.docker
    14  
    15  
    16  def test_missing_key_file(crowdsec, flavor):
    17      """Test that cscli and agent can communicate to LAPI with TLS"""
    18  
    19      env = {
    20          'CERT_FILE': '/etc/ssl/crowdsec/cert.pem',
    21          'USE_TLS': 'true',
    22      }
    23  
    24      with crowdsec(flavor=flavor, environment=env, wait_status=Status.EXITED) as cs:
    25          cs.wait_for_log("*local API server stopped with error: missing TLS key file*")
    26  
    27  
    28  def test_missing_cert_file(crowdsec, flavor):
    29      """Test that cscli and agent can communicate to LAPI with TLS"""
    30  
    31      env = {
    32          'KEY_FILE': '/etc/ssl/crowdsec/cert.key',
    33          'USE_TLS': 'true',
    34      }
    35  
    36      with crowdsec(flavor=flavor, environment=env, wait_status=Status.EXITED) as cs:
    37          cs.wait_for_log("*local API server stopped with error: missing TLS cert file*")
    38  
    39  
    40  def test_tls_missing_ca(crowdsec, flavor, certs_dir):
    41      """Missing CA cert, unknown authority"""
    42  
    43      env = {
    44          'CERT_FILE': '/etc/ssl/crowdsec/lapi.crt',
    45          'KEY_FILE': '/etc/ssl/crowdsec/lapi.key',
    46          'USE_TLS': 'true',
    47          'LOCAL_API_URL': 'https://localhost:8080',
    48      }
    49  
    50      volumes = {
    51          certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
    52      }
    53  
    54      with crowdsec(flavor=flavor, environment=env, volumes=volumes, wait_status=Status.EXITED) as cs:
    55          cs.wait_for_log("*certificate signed by unknown authority*")
    56  
    57  
    58  def test_tls_legacy_var(crowdsec, flavor, certs_dir):
    59      """Test server-only certificate, legacy variables"""
    60  
    61      env = {
    62          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
    63          'CERT_FILE': '/etc/ssl/crowdsec/lapi.crt',
    64          'KEY_FILE': '/etc/ssl/crowdsec/lapi.key',
    65          'USE_TLS': 'true',
    66          'LOCAL_API_URL': 'https://localhost:8080',
    67      }
    68  
    69      volumes = {
    70          certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
    71      }
    72  
    73      with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs:
    74          cs.wait_for_log("*Starting processing data*")
    75          # TODO: wait_for_https
    76          cs.wait_for_http(8080, '/health', want_status=None)
    77          x = cs.cont.exec_run('cscli lapi status')
    78          assert x.exit_code == 0
    79          stdout = x.output.decode()
    80          assert "You can successfully interact with Local API (LAPI)" in stdout
    81  
    82  
    83  def test_tls_mutual_monolith(crowdsec, flavor, certs_dir):
    84      """Server and client certificates, on the same container"""
    85  
    86      env = {
    87          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
    88          'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt',
    89          'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key',
    90          'CLIENT_CERT_FILE': '/etc/ssl/crowdsec/agent.crt',
    91          'CLIENT_KEY_FILE': '/etc/ssl/crowdsec/agent.key',
    92          'USE_TLS': 'true',
    93          'LOCAL_API_URL': 'https://localhost:8080',
    94      }
    95  
    96      volumes = {
    97          certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
    98      }
    99  
   100      with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs:
   101          cs.wait_for_log("*Starting processing data*")
   102          # TODO: wait_for_https
   103          cs.wait_for_http(8080, '/health', want_status=None)
   104          x = cs.cont.exec_run('cscli lapi status')
   105          assert x.exit_code == 0
   106          stdout = x.output.decode()
   107          assert "You can successfully interact with Local API (LAPI)" in stdout
   108  
   109  
   110  def test_tls_lapi_var(crowdsec, flavor, certs_dir):
   111      """Test server-only certificate, lapi variables"""
   112  
   113      env = {
   114          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
   115          'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt',
   116          'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key',
   117          'USE_TLS': 'true',
   118          'LOCAL_API_URL': 'https://localhost:8080',
   119      }
   120  
   121      volumes = {
   122          certs_dir(lapi_hostname='lapi'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
   123      }
   124  
   125      with crowdsec(flavor=flavor, environment=env, volumes=volumes) as cs:
   126          cs.wait_for_log("*Starting processing data*")
   127          # TODO: wait_for_https
   128          cs.wait_for_http(8080, '/health', want_status=None)
   129          x = cs.cont.exec_run('cscli lapi status')
   130          assert x.exit_code == 0
   131          stdout = x.output.decode()
   132          assert "You can successfully interact with Local API (LAPI)" in stdout
   133  
   134  # TODO: bad lapi hostname
   135  # the cert is valid, but has a CN that doesn't match the hostname
   136  # we must set insecure_skip_verify to true to use it
   137  
   138  
   139  def test_tls_split_lapi_agent(crowdsec, flavor, certs_dir):
   140      """Server-only certificate, split containers"""
   141  
   142      rand = uuid.uuid1()
   143      lapiname = 'lapi-' + str(rand)
   144      agentname = 'agent-' + str(rand)
   145  
   146      lapi_env = {
   147          'USE_TLS': 'true',
   148          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
   149          'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt',
   150          'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key',
   151          'AGENT_USERNAME': 'testagent',
   152          'AGENT_PASSWORD': 'testpassword',
   153          'LOCAL_API_URL': 'https://localhost:8080',
   154      }
   155  
   156      agent_env = {
   157          'USE_TLS': 'true',
   158          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
   159          'AGENT_USERNAME': 'testagent',
   160          'AGENT_PASSWORD': 'testpassword',
   161          'LOCAL_API_URL': f'https://{lapiname}:8080',
   162          'DISABLE_LOCAL_API': 'true',
   163          'CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF': 'false',
   164      }
   165  
   166      volumes = {
   167          certs_dir(lapi_hostname=lapiname): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
   168      }
   169  
   170      cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes)
   171      cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes)
   172  
   173      with cs_lapi as lapi:
   174          lapi.wait_for_log([
   175              "*(tls) Client Auth Type set to VerifyClientCertIfGiven*",
   176              "*CrowdSec Local API listening on *:8080*"
   177          ])
   178          # TODO: wait_for_https
   179          lapi.wait_for_http(8080, '/health', want_status=None)
   180          with cs_agent as agent:
   181              agent.wait_for_log("*Starting processing data*")
   182              res = agent.cont.exec_run('cscli lapi status')
   183              assert res.exit_code == 0
   184              stdout = res.output.decode()
   185              assert "You can successfully interact with Local API (LAPI)" in stdout
   186              res = lapi.cont.exec_run('cscli lapi status')
   187              assert res.exit_code == 0
   188              stdout = res.output.decode()
   189              assert "You can successfully interact with Local API (LAPI)" in stdout
   190  
   191  
   192  def test_tls_mutual_split_lapi_agent(crowdsec, flavor, certs_dir):
   193      """Server and client certificates, split containers"""
   194  
   195      rand = uuid.uuid1()
   196      lapiname = 'lapi-' + str(rand)
   197      agentname = 'agent-' + str(rand)
   198  
   199      lapi_env = {
   200          'USE_TLS': 'true',
   201          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
   202          'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt',
   203          'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key',
   204          'LOCAL_API_URL': 'https://localhost:8080',
   205      }
   206  
   207      agent_env = {
   208          'USE_TLS': 'true',
   209          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
   210          'CLIENT_CERT_FILE': '/etc/ssl/crowdsec/agent.crt',
   211          'CLIENT_KEY_FILE': '/etc/ssl/crowdsec/agent.key',
   212          'LOCAL_API_URL': f'https://{lapiname}:8080',
   213          'DISABLE_LOCAL_API': 'true',
   214          'CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF': 'false',
   215      }
   216  
   217      volumes = {
   218          certs_dir(lapi_hostname=lapiname): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
   219      }
   220  
   221      cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes)
   222      cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes)
   223  
   224      with cs_lapi as lapi:
   225          lapi.wait_for_log([
   226              "*(tls) Client Auth Type set to VerifyClientCertIfGiven*",
   227              "*CrowdSec Local API listening on *:8080*"
   228          ])
   229          # TODO: wait_for_https
   230          lapi.wait_for_http(8080, '/health', want_status=None)
   231          with cs_agent as agent:
   232              agent.wait_for_log("*Starting processing data*")
   233              res = agent.cont.exec_run('cscli lapi status')
   234              assert res.exit_code == 0
   235              stdout = res.output.decode()
   236              assert "You can successfully interact with Local API (LAPI)" in stdout
   237              res = lapi.cont.exec_run('cscli lapi status')
   238              assert res.exit_code == 0
   239              stdout = res.output.decode()
   240              assert "You can successfully interact with Local API (LAPI)" in stdout
   241  
   242  
   243  def test_tls_client_ou(crowdsec, flavor, certs_dir):
   244      """Check behavior of client certificate vs AGENTS_ALLOWED_OU"""
   245  
   246      rand = uuid.uuid1()
   247      lapiname = 'lapi-' + str(rand)
   248      agentname = 'agent-' + str(rand)
   249  
   250      lapi_env = {
   251          'USE_TLS': 'true',
   252          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
   253          'LAPI_CERT_FILE': '/etc/ssl/crowdsec/lapi.crt',
   254          'LAPI_KEY_FILE': '/etc/ssl/crowdsec/lapi.key',
   255          'LOCAL_API_URL': 'https://localhost:8080',
   256      }
   257  
   258      agent_env = {
   259          'USE_TLS': 'true',
   260          'CACERT_FILE': '/etc/ssl/crowdsec/ca.crt',
   261          'CLIENT_CERT_FILE': '/etc/ssl/crowdsec/agent.crt',
   262          'CLIENT_KEY_FILE': '/etc/ssl/crowdsec/agent.key',
   263          'LOCAL_API_URL': f'https://{lapiname}:8080',
   264          'DISABLE_LOCAL_API': 'true',
   265          'CROWDSEC_FEATURE_DISABLE_HTTP_RETRY_BACKOFF': 'false',
   266      }
   267  
   268      volumes = {
   269          certs_dir(lapi_hostname=lapiname, agent_ou='custom-client-ou'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
   270      }
   271  
   272      cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes)
   273      cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes)
   274  
   275      with cs_lapi as lapi:
   276          lapi.wait_for_log([
   277              "*(tls) Client Auth Type set to VerifyClientCertIfGiven*",
   278              "*CrowdSec Local API listening on *:8080*"
   279          ])
   280          # TODO: wait_for_https
   281          lapi.wait_for_http(8080, '/health', want_status=None)
   282          with cs_agent as agent:
   283              lapi.wait_for_log([
   284                  "*client certificate OU (?custom-client-ou?) doesn't match expected OU (?agent-ou?)*",
   285              ])
   286  
   287      lapi_env['AGENTS_ALLOWED_OU'] = 'custom-client-ou'
   288  
   289      # change container names to avoid conflict
   290      # recreate certificates because they need the new hostname
   291  
   292      rand = uuid.uuid1()
   293      lapiname = 'lapi-' + str(rand)
   294      agentname = 'agent-' + str(rand)
   295  
   296      agent_env['LOCAL_API_URL'] = f'https://{lapiname}:8080'
   297  
   298      volumes = {
   299          certs_dir(lapi_hostname=lapiname, agent_ou='custom-client-ou'): {'bind': '/etc/ssl/crowdsec', 'mode': 'ro'},
   300      }
   301  
   302      cs_lapi = crowdsec(flavor=flavor, name=lapiname, environment=lapi_env, volumes=volumes)
   303      cs_agent = crowdsec(flavor=flavor, name=agentname, environment=agent_env, volumes=volumes)
   304  
   305      with cs_lapi as lapi:
   306          lapi.wait_for_log([
   307              "*(tls) Client Auth Type set to VerifyClientCertIfGiven*",
   308              "*CrowdSec Local API listening on *:8080*"
   309          ])
   310          # TODO: wait_for_https
   311          lapi.wait_for_http(8080, '/health', want_status=None)
   312          with cs_agent as agent:
   313              agent.wait_for_log("*Starting processing data*")
   314              res = agent.cont.exec_run('cscli lapi status')
   315              assert res.exit_code == 0
   316              stdout = res.output.decode()
   317              assert "You can successfully interact with Local API (LAPI)" in stdout
   318              res = lapi.cont.exec_run('cscli lapi status')
   319              assert res.exit_code == 0
   320              stdout = res.output.decode()
   321              assert "You can successfully interact with Local API (LAPI)" in stdout