Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce data connectors, used to validate if vin is allowed to connect #177

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

patrickdemers6
Copy link
Collaborator

Description

Introduces the concept of data connectors which can use externally provided data to enhance server functionality.

The data connectors supported so far:

  • Redis
  • HTTP
  • File
  • gRPC

To start, data connectors are used for one capability: checking if a vin is allowed before allowing it to send data to the server. This prevents a compromised vehicle from being able to send data to a random fleet-telemetry server.

Please select all options that apply to this change:

  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Bug fix (non-breaking change which fixes an issue)
  • Documentation update

Checklist:

Confirm you have completed the following steps:

  • My code follows the style of this project.
  • I have performed a self-review of my code.
  • I have made corresponding updates to the documentation.
  • I have added/updated unit tests to cover my changes.
  • I have added/updated integration tests to cover my changes.

Other Notes

  • To generate gRPC service protos, additional dependencies are needed. The generation of protos is now handled by a Docker container.
  • General dependency upgrades.
    • Ginkgo no longer supports SlowSpecThreshold so it has been removed.

@patrickdemers6 patrickdemers6 force-pushed the data-connectors-vin-allowed branch from f1edc57 to 1371902 Compare June 10, 2024 04:16
switch name {
case "vin_allowed":
if c.VinAllowedConnector != nil {
c.logger.Log(logrus.WARN, "vin_allowed capability specified multiple times", logrus.LogInfo{})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh, last connector wins!

@patrickdemers6
Copy link
Collaborator Author

I'd like to reject connection before web socket is established but am not having success. Getting that working can be a followup if someone wants to work on it.

@sjmiller609
Copy link

I'd like to reject connection before web socket is established but am not having success. Getting that working can be a followup if someone wants to work on it.

I have similar code in my server, for what it's worth I can give some information for any who may be looking at this PR or a follow up later. Vehicles connect to a telemetry server and present a client certificate. The client certificate includes the VIN in the subject DN. It is therefore possible to terminate the connection based on a VIN list during or at some point after client certificate validation.

My custom telemetry server uses nginx for client certificate validation and TLS termination, see this configuration snippet.

    server {
        .... omitting unrelated ...
        
        # SSL client verification settings for WebSocket
        ssl_client_certificate /certs/tesla-ca.pem;
        ssl_verify_client on;
        
        # WebSocket path(s) only
        location ~ ^/(ws)?$ {
        
            .... omitting unrelated ...
            
            proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
            proxy_pass http://app_servers;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_cache_bypass $http_upgrade;
        }
    }

I am doing something similar in my server to check VIN, but for my purpose it is to use certificate validation to check vehicles only send data for their own VIN. I check that after the websocket is established, I compare the VIN in the header (which comes from the client cert) to what's in the telemetry payload to make sure they are a match.

#[get("/")]
pub async fn websocket_handler(
    req: HttpRequest,
    stream: web::Payload,
    pool: web::Data<PgPool>,
) -> Result<HttpResponse, Error> {
    // Extract client certificate DN from header
    let client_dn = req
        .headers()
        .get("X-SSL-Client-DN")
        .and_then(|h| h.to_str().ok())
        .and_then(extract_vin_from_dn)
        .ok_or_else(|| {
            actix_web::error::ErrorUnauthorized("Invalid or missing client certificate")
        })?;

    let (res, session, msg_stream) = actix_ws::handle(&req, stream)?;

    // Spawn websocket handler with the authorized VIN
    actix_web::rt::spawn(handle_websocket(session, msg_stream, pool, client_dn));

    Ok(res)
}

It seems to me like it would be possible to check the headers right before the websocket is established. Not sure if this helps anyone looking to work on this PR, and I am not sure it's applicable as I did not understand all the code in this PR. I also think it would be possible to terminate the connection even earlier than this, presumably during client certificate validation rather than after that during the HTTP part before the websocket is established.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants