Note d’ingénierie

Tester une API locale depuis un Mac distant avec un tunnel SSH

Mac à distance ·~7 min de lecture

Tester une API locale depuis un Mac distant avec un tunnel SSH

Vous avez lancé sur votre poste de développement une API qui n’est pas encore déployée, tandis que le projet Xcode et les scripts de build s’exécutent sur un Mac dans le cloud. Ouvrir directement un port sur le routeur est à la fois laborieux et risqué, car cela augmente la surface d’attaque. Remplacer temporairement l’adresse dans le dépôt par un domaine public peut également laisser des modifications indésirables dans la configuration. Une approche plus sûre consiste à initier la connexion SSH depuis le poste de développement, puis à utiliser un tunnel inverse pour exposer le port local uniquement sur l’adresse de bouclage du Mac distant.

Vérifier d’abord le sens du trafic

Un tunnel inverse répond au besoin « accéder au poste local depuis le cloud ». Supposons que l’API s’exécute sur 127.0.0.1:8080 sur le poste de développement et que le Mac distant doive l’appeler via 127.0.0.1:18080. La connexion SSH est initiée depuis le poste de développement vers le Mac distant, puis le trafic reçu côté cloud est renvoyé vers le port local.

La redirection locale fonctionne dans l’autre sens : le poste de développement doit accéder à un service de débogage du Mac distant qui écoute uniquement sur son adresse de bouclage. Par exemple, un service distant disponible sur 127.0.0.1:9000 peut être rendu accessible sur 127.0.0.1:19000 depuis le poste de développement.

Objectif Paramètre SSH Machine qui initie la connexion Point d’accès
Accéder à l’API locale depuis le Mac distant -R Poste de développement 127.0.0.1:18080 sur le Mac distant
Accéder au service de débogage distant en local -L Poste de développement 127.0.0.1:19000 en local

Avant de diagnostiquer le tunnel, vérifiez avec un vrai client que le service source répond correctement :

curl -i http://127.0.0.1:8080/health
lsof -nP -iTCP:8080 -sTCP:LISTEN

Si l’application ne propose pas de route de vérification d’état, vous pouvez lancer temporairement un serveur de test qui écoute uniquement en local :

python3 -m http.server 8080 --bind 127.0.0.1

Créer un tunnel inverse avec une exposition minimale

Définissez l’adresse du Mac distant sur le poste de développement, puis exécutez :

export CLOUD_MAC_IP="你的节点地址"
ssh -N \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=30 \
  -o ServerAliveCountMax=3 \
  -R 127.0.0.1:18080:127.0.0.1:8080 \
  dev@"$CLOUD_MAC_IP"

L’option -N indique qu’aucune commande distante ne doit être exécutée : la connexion sert uniquement à transférer le trafic. ExitOnForwardFailure évite de conserver une session SSH apparemment fonctionnelle lorsque l’ouverture du port a échoué. Les deux paramètres de maintien de connexion permettent de détecter une session inactive, mais ils ne recréent pas automatiquement le tunnel après une coupure réseau.

Ouvrez un autre terminal sur le Mac distant pour effectuer les vérifications suivantes :

lsof -nP -iTCP:18080 -sTCP:LISTEN
curl -i http://127.0.0.1:18080/health

Dans la sortie de lsof, l’adresse d’écoute doit être 127.0.0.1:18080, et non *:18080. L’adresse utilisée pour les tests d’intégration doit également être définie dans les variables d’environnement de développement plutôt que codée en dur dans les sources :

export DEV_API_BASE_URL="http://127.0.0.1:18080"
xcodebuild -scheme DemoApp -configuration Debug test

Le tunnel chiffre le transport et limite le point d’entrée, mais ne remplace pas l’authentification propre à l’API. Même si le port écoute uniquement sur l’adresse de bouclage, conservez les jetons de test, les contrôles d’autorisation et des journaux expurgés des données sensibles.

Réduire les erreurs avec la configuration SSH

La saisie répétée d’une longue commande augmente le risque d’inverser le port local, le port distant ou l’adresse cible. Créez plutôt une entrée dédiée dans le fichier ~/.ssh/config du poste de développement :

Host minid-api-tunnel
    HostName CLOUD_MAC_IP
    User dev
    RemoteForward 127.0.0.1:18080 127.0.0.1:8080
    ExitOnForwardFailure yes
    ServerAliveInterval 30
    ServerAliveCountMax 3

Remplacez CLOUD_MAC_IP par l’adresse réelle du nœud, puis vérifiez les permissions du fichier de configuration :

chmod 700 ~/.ssh
chmod 600 ~/.ssh/config
ssh -N minid-api-tunnel

Évitez de regrouper de nombreuses redirections sans rapport dans une même entrée. Utilisez un alias par projet et répartissez les ports selon leur fonction, par exemple 18080 pour l’API et 19000 pour un panneau de débogage. Vous pourrez ainsi identifier le projet à partir du port en écoute et réduire le risque de conflit lorsqu’un nœud est partagé entre plusieurs personnes.

Pour accéder à un service distant depuis le poste local, créez séparément une redirection locale :

ssh -N \
  -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:19000:127.0.0.1:9000 \
  dev@"$CLOUD_MAC_IP"

Accédez ensuite à http://127.0.0.1:19000 uniquement depuis le poste de développement. Aucun des deux modes de redirection n’exige que le service applicatif écoute sur une interface réseau publique.

Diagnostiquer les échecs de connexion couche par couche

Pour diagnostiquer un tunnel, contrôlez successivement le service source, la redirection SSH et le client cible. Vous éviterez ainsi de modifier simultanément le pare-feu, la configuration de l’application et le code du projet.

Couche du service source

Exécutez curl et lsof sur le poste de développement. Si l’API écoute uniquement sur l’adresse IPv6 ::1 alors que la cible de la redirection est 127.0.0.1, la connexion sera refusée. Utilisez le même protocole d’écoute des deux côtés ou remplacez la cible de la redirection par l’adresse réellement utilisée. Vérifiez également qu’aucun proxy local n’intercepte le trafic de bouclage. Pour l’exclure temporairement, utilisez :

curl --noproxy '*' -i http://127.0.0.1:8080/health

Couche de redirection SSH

Activez la sortie détaillée pour vérifier le résultat de la demande d’ouverture du port :

ssh -vv -N \
  -o ExitOnForwardFailure=yes \
  -R 127.0.0.1:18080:127.0.0.1:8080 \
  dev@"$CLOUD_MAC_IP"

Si SSH signale un échec de la redirection de port distante, essayez d’abord un port libre. Si le problème persiste, vérifiez que le service SSH du Mac distant autorise la redirection TCP. Ne contournez pas le problème en écoutant sur une interface publique ou en autorisant toutes les sources.

Couche du client cible

Le fait que curl fonctionne dans le terminal distant ne garantit pas que toutes les cibles d’exécution bénéficient automatiquement des mêmes conditions réseau. Les scripts de build, les applications graphiques et les simulateurs peuvent charger des configurations d’environnement différentes. Les requêtes HTTP peuvent également être soumises aux règles de sécurité du projet. Relevez séparément le processus appelant, l’URL cible, le code de réponse et le délai d’expiration afin de déterminer s’il s’agit d’un problème réseau ou d’un refus au niveau applicatif.

Vérifications avant utilisation et nettoyage

Une fois les tests d’intégration terminés, arrêtez d’abord les tâches qui dépendent du tunnel, puis fermez la session SSH. Utilisez lsof pour confirmer que le port redirigé n’est plus présent, et supprimez du projet les adresses temporaires, les jetons de test et les journaux de débogage.

Avant de valider le code, contrôlez au minimum les points suivants :

  • L’API écoute toujours uniquement sur l’adresse de bouclage du poste de développement.
  • Le port redirigé sur le Mac distant écoute uniquement sur 127.0.0.1.
  • Les permissions de la clé privée SSH sont définies sur 600 et celles du répertoire de configuration sur 700.
  • Le projet sélectionne l’adresse d’intégration via une variable d’environnement, et la configuration de production ne référence pas ce port.
  • Les journaux ne contiennent ni jetons de requête, ni clés, ni données utilisateur complètes, ni en-têtes d’authentification.
  • Si le projet est partagé, le numéro de port, la personne responsable et l’heure de fin sont consignés.

Cette méthode convient aux API temporaires, à la validation de callbacks et aux tests d’intégration avec des builds distants. Si plusieurs nœuds doivent accéder durablement au service, utilisez un déploiement formel doté de ses propres mécanismes d’authentification, de contrôle d’accès et d’audit, plutôt que de transformer un tunnel temporaire en point d’entrée de production.

Questions fréquentes

Le tunnel SSH inversé expose-t-il l’API locale sur Internet ?

Non si le port distant écoute explicitement sur 127.0.0.1. Il reste alors accessible uniquement depuis le Mac distant. Vérifiez l’adresse d’écoute et n’utilisez pas 0.0.0.0.

Pourquoi le port distant reste-t-il inaccessible après la connexion SSH ?

Vérifiez d’abord que l’API locale écoute sur le bon port, puis contrôlez le port distant avec lsof. Un port déjà occupé ou le refus du transfert TCP par le serveur sont les causes les plus fréquentes.

Une application lancée depuis Xcode peut-elle utiliser directement le tunnel ?

Les scripts exécutés sur le Mac distant peuvent utiliser l’adresse locale du tunnel. Pour un simulateur ou une application, vérifiez aussi son espace réseau et les règles de sécurité HTTP du projet.

MiniD Cloud Mac

Louez un Mac mini physique dédié à la journée, à la semaine ou au mois

Chaque offre repose sur un Mac mini physique dédié, accessible en bureau à distance et en SSH ; les modèles, régions et durées disponibles figurent sur la page de commande.

Voir les options de commande