I put the following JSON file on my computer in a file called test.json
{
    "title": "Example Schema",
    "type": "object",
    "properties": {
       "firstName": {
         "type": "string"
       },
       "lastName": {
         "type": "string"
       },
       "age": {
         "description": "Age in years",
         "type": "integer",
         "minimum": 0
       }
    },
    "required": ["firstName", "lastName"]
}
When I import it I get the following:
jsonData=Import["/Users/dreiss/Desktop/test.json"]
which gives the following:
{"required" -> {"firstName", "lastName"}, "title" -> "Example Schema",
  "type" -> "object", 
 "properties" -> {"firstName" -> {"type" -> "string"}, 
   "lastName" -> {"type" -> "string"}, 
   "age" -> {"description" -> "Age in years", "minimum" -> 0, 
     "type" -> "integer"}}}
Note that this is somewhat more nested than your example.  If you want the left hand sides of the rules at the very top level just execute
First/@jsonData
which returns
{"required", "title", "type", "properties"}
Let's say you want all of the left hand sides of all rules then this would do the trick:
Cases[jsonData, (z_ -> _) :> z, Infinity]
which returns
{"required", "title", "type", "type", "firstName", "type", \
"lastName", "description", "minimum", "type", "age", "properties"}
By the way leaving out the Infinity, gives the same answer as the original computation which asks for just the first level:
Cases[jsonData, (z_ -> _) :> z]
returns
{"required", "title", "type", "properties"}
Let's say though though you want only the left hand sides all the way to only the third level
Cases[jsonData, (z_ -> _) :> z, 3]
gives
{"required", "title", "type", "firstName", "lastName", "age", \
"properties"}
And if you want it only at just the 3rd level you'd use this
Cases[jsonData, (z_ -> _) :> z, {3}]
which gives this:
{"firstName", "lastName", "age"}