You can adapt my solution for a similar problem.  It uses scrap-your-boilerplate (SYB) generics.  That answer explains the code in a fair bit of detail, so I won't explain it here.  Below is  sample code that works with your example.  It supports data types with a mixture of Maybe String and String fields; other field types are ignored by getKey.
Note that this is not going to be very efficient.  If this is a core part of your application logic, rather than some debugging hack, you should consider rethinking your data types.  Maybe you don't actually want a Haskell record type here, but rather some kind of bi-directional map (e.g., a Map k v and Map v k paired together accessed through a set of functions that keep them consistent).
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
import Data.Tuple
import Data.Generics
data HaskellRecord = HaskellRecord {
  _key1 :: Maybe String
, _key2 :: Maybe String
, _key3 :: Maybe String
} deriving (Data)
-- Get field names (empty list if not record constructor)
getnames :: Data object => object -> [String]
getnames = constrFields . toConstr
-- Get field values as `Maybe String`s
getfields :: Data object => object -> [Maybe String]
getfields = gmapQ toString
-- Generic function to convert one field.
toString :: (Data a) => a -> Maybe String
toString = mkQ    Nothing        -- make a query with default value Nothing
                  id             -- handle:          id     :: Maybe String -> Maybe String
           `extQ` Just           -- extend to:       Just   :: String -> Maybe String
-- Get field name/value pairs from any `Data` object.
getpairs :: Data object => object -> [(String, Maybe String)]
getpairs = zip <$> getnames <*> getfields
getKey :: Data record => String -> record -> Maybe String
getKey v = lookup (Just v) . map swap . getpairs
main :: IO ()
main = do
  print $ getKey "value2" $
    HaskellRecord {
      _key1 = Just "value1",
      _key2 = Just "value2",
      _key3 = Just "value3"
      }